Skip to content

Commit 6c949c0

Browse files
Merge branch 'main' into fix-jit-make
2 parents 178cebd + 2a87af0 commit 6c949c0

File tree

13 files changed

+182
-54
lines changed

13 files changed

+182
-54
lines changed

Doc/library/calendar.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,14 @@ The :mod:`calendar` module exports the following data attributes:
501501
>>> list(calendar.month_name)
502502
['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
503503

504+
.. caution::
505+
506+
In locales with alternative month names forms, the :data:`!month_name` sequence
507+
may not be suitable when a month name stands by itself and not as part of a date.
508+
For instance, in Greek and in many Slavic and Baltic languages, :data:`!month_name`
509+
will produce the month in genitive case. Use :data:`standalone_month_name` for a form
510+
suitable for standalone use.
511+
504512

505513
.. data:: month_abbr
506514

@@ -512,6 +520,31 @@ The :mod:`calendar` module exports the following data attributes:
512520
>>> list(calendar.month_abbr)
513521
['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
514522

523+
.. caution::
524+
525+
In locales with alternative month names forms, the :data:`!month_abbr` sequence
526+
may not be suitable when a month name stands by itself and not as part of a date.
527+
Use :data:`standalone_month_abbr` for a form suitable for standalone use.
528+
529+
530+
.. data:: standalone_month_name
531+
532+
A sequence that represents the months of the year in the current locale
533+
in the standalone form if the locale provides one. Else it is equivalent
534+
to :data:`month_name`.
535+
536+
.. versionadded:: next
537+
538+
539+
.. data:: standalone_month_abbr
540+
541+
A sequence that represents the abbreviated months of the year in the current
542+
locale in the standalone form if the locale provides one. Else it is
543+
equivalent to :data:`month_abbr`.
544+
545+
.. versionadded:: next
546+
547+
515548
.. data:: JANUARY
516549
FEBRUARY
517550
MARCH

Lib/ast.py

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -57,53 +57,60 @@ def literal_eval(node_or_string):
5757
Caution: A complex expression can overflow the C stack and cause a crash.
5858
"""
5959
if isinstance(node_or_string, str):
60-
node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval')
61-
if isinstance(node_or_string, Expression):
60+
node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval').body
61+
elif isinstance(node_or_string, Expression):
6262
node_or_string = node_or_string.body
63-
def _raise_malformed_node(node):
64-
msg = "malformed node or string"
65-
if lno := getattr(node, 'lineno', None):
66-
msg += f' on line {lno}'
67-
raise ValueError(msg + f': {node!r}')
68-
def _convert_num(node):
69-
if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
70-
_raise_malformed_node(node)
63+
return _convert_literal(node_or_string)
64+
65+
66+
def _convert_literal(node):
67+
"""
68+
Used by `literal_eval` to convert an AST node into a value.
69+
"""
70+
if isinstance(node, Constant):
7171
return node.value
72-
def _convert_signed_num(node):
73-
if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
74-
operand = _convert_num(node.operand)
75-
if isinstance(node.op, UAdd):
76-
return + operand
77-
else:
78-
return - operand
79-
return _convert_num(node)
80-
def _convert(node):
81-
if isinstance(node, Constant):
82-
return node.value
83-
elif isinstance(node, Tuple):
84-
return tuple(map(_convert, node.elts))
85-
elif isinstance(node, List):
86-
return list(map(_convert, node.elts))
87-
elif isinstance(node, Set):
88-
return set(map(_convert, node.elts))
89-
elif (isinstance(node, Call) and isinstance(node.func, Name) and
90-
node.func.id == 'set' and node.args == node.keywords == []):
91-
return set()
92-
elif isinstance(node, Dict):
93-
if len(node.keys) != len(node.values):
94-
_raise_malformed_node(node)
95-
return dict(zip(map(_convert, node.keys),
96-
map(_convert, node.values)))
97-
elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
98-
left = _convert_signed_num(node.left)
99-
right = _convert_num(node.right)
100-
if isinstance(left, (int, float)) and isinstance(right, complex):
101-
if isinstance(node.op, Add):
102-
return left + right
103-
else:
104-
return left - right
105-
return _convert_signed_num(node)
106-
return _convert(node_or_string)
72+
if isinstance(node, Dict) and len(node.keys) == len(node.values):
73+
return dict(zip(
74+
map(_convert_literal, node.keys),
75+
map(_convert_literal, node.values),
76+
))
77+
if isinstance(node, Tuple):
78+
return tuple(map(_convert_literal, node.elts))
79+
if isinstance(node, List):
80+
return list(map(_convert_literal, node.elts))
81+
if isinstance(node, Set):
82+
return set(map(_convert_literal, node.elts))
83+
if (
84+
isinstance(node, Call) and isinstance(node.func, Name)
85+
and node.func.id == 'set' and node.args == node.keywords == []
86+
):
87+
return set()
88+
if (
89+
isinstance(node, UnaryOp)
90+
and isinstance(node.op, (UAdd, USub))
91+
and isinstance(node.operand, Constant)
92+
and type(operand := node.operand.value) in (int, float, complex)
93+
):
94+
if isinstance(node.op, UAdd):
95+
return + operand
96+
else:
97+
return - operand
98+
if (
99+
isinstance(node, BinOp)
100+
and isinstance(node.op, (Add, Sub))
101+
and isinstance(node.left, (Constant, UnaryOp))
102+
and isinstance(node.right, Constant)
103+
and type(left := _convert_literal(node.left)) in (int, float)
104+
and type(right := _convert_literal(node.right)) is complex
105+
):
106+
if isinstance(node.op, Add):
107+
return left + right
108+
else:
109+
return left - right
110+
msg = "malformed node or string"
111+
if lno := getattr(node, 'lineno', None):
112+
msg += f' on line {lno}'
113+
raise ValueError(msg + f': {node!r}')
107114

108115

109116
def dump(

Lib/calendar.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
__all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
1515
"firstweekday", "isleap", "leapdays", "weekday", "monthrange",
1616
"monthcalendar", "prmonth", "month", "prcal", "calendar",
17-
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
18-
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
17+
"timegm", "month_name", "month_abbr", "standalone_month_name",
18+
"standalone_month_abbr", "day_name", "day_abbr", "Calendar",
19+
"TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
1920
"LocaleHTMLCalendar", "weekheader",
2021
"Day", "Month", "JANUARY", "FEBRUARY", "MARCH",
2122
"APRIL", "MAY", "JUNE", "JULY",
@@ -139,6 +140,16 @@ def __len__(self):
139140
month_name = _localized_month('%B')
140141
month_abbr = _localized_month('%b')
141142

143+
# On platforms that support the %OB and %Ob specifiers, they are used
144+
# to get the standalone form of the month name. This is required for
145+
# some languages such as Greek, Slavic, and Baltic languages.
146+
try:
147+
standalone_month_name = _localized_month('%OB')
148+
standalone_month_abbr = _localized_month('%Ob')
149+
except ValueError:
150+
standalone_month_name = month_name
151+
standalone_month_abbr = month_abbr
152+
142153

143154
def isleap(year):
144155
"""Return True for leap years, False for non-leap years."""
@@ -377,7 +388,7 @@ def formatmonthname(self, theyear, themonth, width, withyear=True):
377388
"""
378389
_validate_month(themonth)
379390

380-
s = month_name[themonth]
391+
s = standalone_month_name[themonth]
381392
if withyear:
382393
s = "%s %r" % (s, theyear)
383394
return s.center(width)
@@ -510,9 +521,9 @@ def formatmonthname(self, theyear, themonth, withyear=True):
510521
"""
511522
_validate_month(themonth)
512523
if withyear:
513-
s = '%s %s' % (month_name[themonth], theyear)
524+
s = '%s %s' % (standalone_month_name[themonth], theyear)
514525
else:
515-
s = '%s' % month_name[themonth]
526+
s = standalone_month_name[themonth]
516527
return '<tr><th colspan="7" class="%s">%s</th></tr>' % (
517528
self.cssclass_month_head, s)
518529

Lib/concurrent/futures/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545

4646
def __dir__():
47-
return __all__ + ('__author__', '__doc__')
47+
return __all__ + ['__author__', '__doc__']
4848

4949

5050
def __getattr__(name):

Lib/test/support/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,12 @@ def has_no_debug_ranges():
544544
return not bool(config['code_debug_ranges'])
545545

546546
def requires_debug_ranges(reason='requires co_positions / debug_ranges'):
547-
return unittest.skipIf(has_no_debug_ranges(), reason)
547+
try:
548+
skip = has_no_debug_ranges()
549+
except unittest.SkipTest as e:
550+
skip = True
551+
reason = e.args[0] if e.args else reason
552+
return unittest.skipIf(skip, reason)
548553

549554

550555
MS_WINDOWS = (sys.platform == 'win32')

Lib/test/test___all__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def check_all(self, modname):
7272
all_set = set(all_list)
7373
self.assertCountEqual(all_set, all_list, "in module {}".format(modname))
7474
self.assertEqual(keys, all_set, "in module {}".format(modname))
75+
# Verify __dir__ is non-empty and doesn't produce an error
76+
self.assertTrue(dir(sys.modules[modname]))
7577

7678
def walk_modules(self, basedir, modpath):
7779
for fn in sorted(os.listdir(basedir)):

Lib/test/test_calendar.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io
99
import locale
1010
import os
11+
import platform
1112
import sys
1213
import time
1314

@@ -546,7 +547,8 @@ def test_days(self):
546547
self.assertEqual(value[::-1], list(reversed(value)))
547548

548549
def test_months(self):
549-
for attr in "month_name", "month_abbr":
550+
for attr in ("month_name", "month_abbr", "standalone_month_name",
551+
"standalone_month_abbr"):
550552
value = getattr(calendar, attr)
551553
self.assertEqual(len(value), 13)
552554
self.assertEqual(len(value[:]), 13)
@@ -556,6 +558,38 @@ def test_months(self):
556558
# verify it "acts like a sequence" in two forms of iteration
557559
self.assertEqual(value[::-1], list(reversed(value)))
558560

561+
@support.run_with_locale('LC_ALL', 'pl_PL')
562+
@unittest.skipUnless(sys.platform == 'darwin' or platform.libc_ver()[0] == 'glibc',
563+
"Guaranteed to work with glibc and macOS")
564+
def test_standalone_month_name_and_abbr_pl_locale(self):
565+
expected_standalone_month_names = [
566+
"", "styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec",
567+
"lipiec", "sierpień", "wrzesień", "październik", "listopad",
568+
"grudzień"
569+
]
570+
expected_standalone_month_abbr = [
571+
"", "sty", "lut", "mar", "kwi", "maj", "cze",
572+
"lip", "sie", "wrz", "paź", "lis", "gru"
573+
]
574+
self.assertEqual(
575+
list(calendar.standalone_month_name),
576+
expected_standalone_month_names
577+
)
578+
self.assertEqual(
579+
list(calendar.standalone_month_abbr),
580+
expected_standalone_month_abbr
581+
)
582+
583+
def test_standalone_month_name_and_abbr_C_locale(self):
584+
# Ensure that the standalone month names and abbreviations are
585+
# equal to the regular month names and abbreviations for
586+
# the "C" locale.
587+
with calendar.different_locale("C"):
588+
self.assertListEqual(list(calendar.month_name),
589+
list(calendar.standalone_month_name))
590+
self.assertListEqual(list(calendar.month_abbr),
591+
list(calendar.standalone_month_abbr))
592+
559593
def test_locale_text_calendar(self):
560594
try:
561595
cal = calendar.LocaleTextCalendar(locale='')

Lib/test/test_monitoring.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import collections
44
import dis
55
import functools
6+
import inspect
67
import math
78
import operator
89
import sys
@@ -1709,6 +1710,27 @@ def func(v=1):
17091710
('branch right', 'func', 6, 8),
17101711
('branch right', 'func', 2, 10)])
17111712

1713+
def test_callback_set_frame_lineno(self):
1714+
def func(s: str) -> int:
1715+
if s.startswith("t"):
1716+
return 1
1717+
else:
1718+
return 0
1719+
1720+
def callback(code, from_, to):
1721+
# try set frame.f_lineno
1722+
frame = inspect.currentframe()
1723+
while frame and frame.f_code is not code:
1724+
frame = frame.f_back
1725+
1726+
self.assertIsNotNone(frame)
1727+
frame.f_lineno = frame.f_lineno + 1 # run next instruction
1728+
1729+
sys.monitoring.set_local_events(TEST_TOOL, func.__code__, E.BRANCH_LEFT)
1730+
sys.monitoring.register_callback(TEST_TOOL, E.BRANCH_LEFT, callback)
1731+
1732+
self.assertEqual(func("true"), 1)
1733+
17121734

17131735
class TestBranchConsistency(MonitoringTestBase, unittest.TestCase):
17141736

Makefile.pre.in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,10 @@ web_example/index.html: $(WEBEX_DIR)/index.html
11211121
@mkdir -p web_example
11221122
@cp $< $@
11231123

1124+
web_example/python.worker.mjs: $(WEBEX_DIR)/python.worker.mjs
1125+
@mkdir -p web_example
1126+
@cp $< $@
1127+
11241128
web_example/server.py: $(WEBEX_DIR)/server.py
11251129
@mkdir -p web_example
11261130
@cp $< $@
@@ -1138,7 +1142,7 @@ web_example/python.mjs web_example/python.wasm: $(BUILDPYTHON)
11381142
cp python.wasm web_example/python.wasm
11391143

11401144
.PHONY: web_example
1141-
web_example: web_example/python.mjs web_example/index.html web_example/server.py web_example/$(ZIP_STDLIB)
1145+
web_example: web_example/python.mjs web_example/python.worker.mjs web_example/index.html web_example/server.py web_example/$(ZIP_STDLIB)
11421146

11431147
WEBEX2=web_example_pyrepl_jspi
11441148
WEBEX2_DIR=$(EMSCRIPTEN_DIR)/$(WEBEX2)/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Fix :class:`calendar.TextCalendar`, :class:`calendar.HTMLCalendar`,
2+
and the :mod:`calendar` CLI to display month names in the nominative
3+
case by adding :data:`calendar.standalone_month_name` and
4+
:data:`calendar.standalone_month_abbr`, which provide month names and
5+
abbreviations in the grammatical form used when a month name stands by
6+
itself, if the locale supports it.

0 commit comments

Comments
 (0)