Skip to content

Commit d62099e

Browse files
authored
Merge pull request #546 from python/main
Sync Fork from Upstream Repo
2 parents 6343dfb + fbc349f commit d62099e

File tree

5 files changed

+70
-10
lines changed

5 files changed

+70
-10
lines changed

Diff for: Lib/test/test_typing.py

+23
Original file line numberDiff line numberDiff line change
@@ -3691,6 +3691,29 @@ def test_errors(self):
36913691
class D(UserName):
36923692
pass
36933693

3694+
def test_or(self):
3695+
UserId = NewType('UserId', int)
3696+
UserName = NewType('UserName', str)
3697+
3698+
for cls in (int, UserName):
3699+
with self.subTest(cls=cls):
3700+
self.assertEqual(UserId | cls, Union[UserId, cls])
3701+
self.assertEqual(cls | UserId, Union[cls, UserId])
3702+
3703+
self.assertEqual(get_args(UserId | cls), (UserId, cls))
3704+
self.assertEqual(get_args(cls | UserId), (cls, UserId))
3705+
3706+
def test_special_attrs(self):
3707+
UserId = NewType('UserId', int)
3708+
3709+
self.assertEqual(UserId.__name__, 'UserId')
3710+
self.assertEqual(UserId.__qualname__, 'UserId')
3711+
self.assertEqual(UserId.__module__, __name__)
3712+
3713+
def test_repr(self):
3714+
UserId = NewType('UserId', int)
3715+
3716+
self.assertEqual(repr(UserId), f'{__name__}.UserId')
36943717

36953718
class NamedTupleTests(BaseTestCase):
36963719
class NestedEmployee(NamedTuple):

Diff for: Lib/typing.py

+22-5
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,12 @@ def _no_init(self, *args, **kwargs):
13741374
if type(self)._is_protocol:
13751375
raise TypeError('Protocols cannot be instantiated')
13761376

1377+
def _callee(depth=2, default=None):
1378+
try:
1379+
return sys._getframe(depth).f_globals['__name__']
1380+
except (AttributeError, ValueError): # For platforms without _getframe()
1381+
return default
1382+
13771383

13781384
def _allow_reckless_class_checks(depth=3):
13791385
"""Allow instance and class checks for special stdlib modules.
@@ -2350,7 +2356,7 @@ class body be required.
23502356
TypedDict.__mro_entries__ = lambda bases: (_TypedDict,)
23512357

23522358

2353-
def NewType(name, tp):
2359+
class NewType:
23542360
"""NewType creates simple unique types with almost zero
23552361
runtime overhead. NewType(name, tp) is considered a subtype of tp
23562362
by static type checkers. At runtime, NewType(name, tp) returns
@@ -2369,12 +2375,23 @@ def name_by_id(user_id: UserId) -> str:
23692375
num = UserId(5) + 1 # type: int
23702376
"""
23712377

2372-
def new_type(x):
2378+
def __init__(self, name, tp):
2379+
self.__name__ = name
2380+
self.__qualname__ = name
2381+
self.__module__ = _callee(default='typing')
2382+
self.__supertype__ = tp
2383+
2384+
def __repr__(self):
2385+
return f'{self.__module__}.{self.__qualname__}'
2386+
2387+
def __call__(self, x):
23732388
return x
23742389

2375-
new_type.__name__ = name
2376-
new_type.__supertype__ = tp
2377-
return new_type
2390+
def __or__(self, other):
2391+
return Union[self, other]
2392+
2393+
def __ror__(self, other):
2394+
return Union[other, self]
23782395

23792396

23802397
# Python-version-specific alias (Python 2: unicode; Python 3: str)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Refactor ``typing.NewType`` from function into callable class. Patch
2+
provided by Yurii Karabas.

Diff for: Parser/pegen.c

+13-5
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset)
402402
{
403403
const char *str = PyUnicode_AsUTF8(line);
404404
if (!str) {
405-
return 0;
405+
return -1;
406406
}
407407
Py_ssize_t len = strlen(str);
408408
if (col_offset > len + 1) {
@@ -411,7 +411,7 @@ _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset)
411411
assert(col_offset >= 0);
412412
PyObject *text = PyUnicode_DecodeUTF8(str, col_offset, "replace");
413413
if (!text) {
414-
return 0;
414+
return -1;
415415
}
416416
Py_ssize_t size = PyUnicode_GET_LENGTH(text);
417417
Py_DECREF(text);
@@ -499,9 +499,17 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype,
499499

500500
if (p->tok->encoding != NULL) {
501501
col_number = _PyPegen_byte_offset_to_character_offset(error_line, col_offset);
502-
end_col_number = end_col_number > 0 ?
503-
_PyPegen_byte_offset_to_character_offset(error_line, end_col_offset) :
504-
end_col_number;
502+
if (col_number < 0) {
503+
goto error;
504+
}
505+
if (end_col_number > 0) {
506+
Py_ssize_t end_col_offset = _PyPegen_byte_offset_to_character_offset(error_line, end_col_number);
507+
if (end_col_offset < 0) {
508+
goto error;
509+
} else {
510+
end_col_number = end_col_offset;
511+
}
512+
}
505513
}
506514
tmp = Py_BuildValue("(OiiNii)", p->tok->filename, lineno, col_number, error_line, end_lineno, end_col_number);
507515
if (!tmp) {

Diff for: Python/traceback.c

+10
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,17 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen
745745
// Convert the utf-8 byte offset to the actual character offset so we print the right number of carets.
746746
assert(source_line);
747747
Py_ssize_t start_offset = _PyPegen_byte_offset_to_character_offset(source_line, start_col_byte_offset);
748+
if (start_offset < 0) {
749+
err = ignore_source_errors() < 0;
750+
goto done;
751+
}
752+
748753
Py_ssize_t end_offset = _PyPegen_byte_offset_to_character_offset(source_line, end_col_byte_offset);
754+
if (end_offset < 0) {
755+
err = ignore_source_errors() < 0;
756+
goto done;
757+
}
758+
749759
Py_ssize_t left_end_offset = -1;
750760
Py_ssize_t right_start_offset = -1;
751761

0 commit comments

Comments
 (0)