Skip to content

Commit c390a03

Browse files
authored
Merge branch 'main' into binary_op_list_list
2 parents 538d072 + 1e79bf6 commit c390a03

File tree

75 files changed

+1376
-252
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1376
-252
lines changed

Doc/c-api/interp-lifecycle.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,11 @@ Initializing and finalizing the interpreter
410410
(zero) if not. After :c:func:`Py_FinalizeEx` is called, this returns false until
411411
:c:func:`Py_Initialize` is called again.
412412
413+
.. versionchanged:: next
414+
This function no longer returns true until initialization has fully
415+
completed, including import of the :mod:`site` module. Previously it
416+
could return true while :c:func:`Py_Initialize` was still running.
417+
413418
414419
.. c:function:: int Py_IsFinalizing()
415420

Doc/library/functions.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ are always available. They are listed here in alphabetical order.
644644
If the given source is a string, then leading and trailing spaces and tabs
645645
are stripped.
646646

647-
See :func:`ast.literal_eval` for a function that can safely evaluate strings
647+
See :func:`ast.literal_eval` for a function to evaluate strings
648648
with expressions containing only literals.
649649

650650
.. audit-event:: exec code_object eval

Doc/library/multiprocessing.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,8 @@ For an example of the usage of queues for interprocess communication see
932932
standard library's :mod:`queue` module are raised to signal timeouts.
933933

934934
:class:`Queue` implements all the methods of :class:`queue.Queue` except for
935-
:meth:`~queue.Queue.task_done` and :meth:`~queue.Queue.join`.
935+
:meth:`~queue.Queue.task_done`, :meth:`~queue.Queue.join`, and
936+
:meth:`~queue.Queue.shutdown`.
936937

937938
.. method:: qsize()
938939

Include/internal/pycore_dict.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ _PyDict_NotifyEvent(PyDict_WatchEvent event,
292292
PyObject *value)
293293
{
294294
assert(Py_REFCNT((PyObject*)mp) > 0);
295-
int watcher_bits = mp->_ma_watcher_tag & DICT_WATCHER_MASK;
295+
int watcher_bits = FT_ATOMIC_LOAD_UINT64_RELAXED(mp->_ma_watcher_tag) & DICT_WATCHER_MASK;
296296
if (watcher_bits) {
297297
RARE_EVENT_STAT_INC(watched_dict_modification);
298298
_PyDict_SendEvent(watcher_bits, event, mp, key, value);
@@ -368,7 +368,7 @@ PyDictObject *_PyObject_MaterializeManagedDict_LockHeld(PyObject *);
368368
static inline Py_ssize_t
369369
_PyDict_UniqueId(PyDictObject *mp)
370370
{
371-
return (Py_ssize_t)(mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT);
371+
return (Py_ssize_t)(FT_ATOMIC_LOAD_UINT64_RELAXED(mp->_ma_watcher_tag) >> DICT_UNIQUE_ID_SHIFT);
372372
}
373373

374374
static inline void

Include/internal/pycore_pyatomic_ft_wrappers.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ extern "C" {
4949
_Py_atomic_load_uint16_relaxed(&value)
5050
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) \
5151
_Py_atomic_load_uint32_relaxed(&value)
52+
#define FT_ATOMIC_LOAD_UINT64_RELAXED(value) \
53+
_Py_atomic_load_uint64_relaxed(&value)
5254
#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) \
5355
_Py_atomic_load_ulong_relaxed(&value)
5456
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) \
@@ -71,6 +73,12 @@ extern "C" {
7173
_Py_atomic_store_uint16_relaxed(&value, new_value)
7274
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) \
7375
_Py_atomic_store_uint32_relaxed(&value, new_value)
76+
#define FT_ATOMIC_AND_UINT64(value, new_value) \
77+
(void)_Py_atomic_and_uint64(&value, new_value)
78+
#define FT_ATOMIC_OR_UINT64(value, new_value) \
79+
(void)_Py_atomic_or_uint64(&value, new_value)
80+
#define FT_ATOMIC_ADD_UINT64(value, new_value) \
81+
(void)_Py_atomic_add_uint64(&value, new_value)
7482
#define FT_ATOMIC_STORE_CHAR_RELAXED(value, new_value) \
7583
_Py_atomic_store_char_relaxed(&value, new_value)
7684
#define FT_ATOMIC_LOAD_CHAR_RELAXED(value) \
@@ -146,6 +154,7 @@ extern "C" {
146154
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value
147155
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value
148156
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value
157+
#define FT_ATOMIC_LOAD_UINT64_RELAXED(value) value
149158
#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) value
150159
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value
151160
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
@@ -157,6 +166,9 @@ extern "C" {
157166
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value
158167
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) value = new_value
159168
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) value = new_value
169+
#define FT_ATOMIC_AND_UINT64(value, new_value) (void)(value &= new_value)
170+
#define FT_ATOMIC_OR_UINT64(value, new_value) (void)(value |= new_value)
171+
#define FT_ATOMIC_ADD_UINT64(value, new_value) (void)(value += new_value)
160172
#define FT_ATOMIC_LOAD_CHAR_RELAXED(value) value
161173
#define FT_ATOMIC_STORE_CHAR_RELAXED(value, new_value) value = new_value
162174
#define FT_ATOMIC_LOAD_UCHAR_RELAXED(value) value

Include/internal/pycore_runtime.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,29 @@ _PyRuntimeState_SetFinalizing(_PyRuntimeState *runtime, PyThreadState *tstate) {
5656
}
5757
}
5858

59+
// Atomic so a thread that reads initialized=1 observes all writes
60+
// from the initialization sequence (gh-146302).
61+
62+
static inline int
63+
_PyRuntimeState_GetCoreInitialized(_PyRuntimeState *runtime) {
64+
return _Py_atomic_load_int(&runtime->core_initialized);
65+
}
66+
67+
static inline void
68+
_PyRuntimeState_SetCoreInitialized(_PyRuntimeState *runtime, int initialized) {
69+
_Py_atomic_store_int(&runtime->core_initialized, initialized);
70+
}
71+
72+
static inline int
73+
_PyRuntimeState_GetInitialized(_PyRuntimeState *runtime) {
74+
return _Py_atomic_load_int(&runtime->initialized);
75+
}
76+
77+
static inline void
78+
_PyRuntimeState_SetInitialized(_PyRuntimeState *runtime, int initialized) {
79+
_Py_atomic_store_int(&runtime->initialized, initialized);
80+
}
81+
5982

6083
#ifdef __cplusplus
6184
}

Include/internal/pycore_runtime_structs.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,18 @@ struct pyruntimestate {
158158
/* Is Python preinitialized? Set to 1 by Py_PreInitialize() */
159159
int preinitialized;
160160

161-
/* Is Python core initialized? Set to 1 by _Py_InitializeCore() */
161+
/* Is Python core initialized? Set to 1 by _Py_InitializeCore().
162+
163+
Use _PyRuntimeState_GetCoreInitialized() and
164+
_PyRuntimeState_SetCoreInitialized() to access it,
165+
don't access it directly. */
162166
int core_initialized;
163167

164-
/* Is Python fully initialized? Set to 1 by Py_Initialize() */
168+
/* Is Python fully initialized? Set to 1 by Py_Initialize().
169+
170+
Use _PyRuntimeState_GetInitialized() and
171+
_PyRuntimeState_SetInitialized() to access it,
172+
don't access it directly. */
165173
int initialized;
166174

167175
/* Set by Py_FinalizeEx(). Only reset to NULL if Py_Initialize()

Lib/idlelib/config.py

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -476,34 +476,58 @@ def GetExtensionKeys(self, extensionName):
476476
Keybindings come from GetCurrentKeySet() active key dict,
477477
where previously used bindings are disabled.
478478
"""
479-
keysName = extensionName + '_cfgBindings'
480-
activeKeys = self.GetCurrentKeySet()
481-
extKeys = {}
482-
if self.defaultCfg['extensions'].has_section(keysName):
483-
eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
484-
for eventName in eventNames:
485-
event = '<<' + eventName + '>>'
486-
binding = activeKeys[event]
487-
extKeys[event] = binding
488-
return extKeys
489-
490-
def __GetRawExtensionKeys(self,extensionName):
479+
bindings_section = f'{extensionName}_cfgBindings'
480+
current_keyset = self.GetCurrentKeySet()
481+
extension_keys = {}
482+
483+
event_names = set()
484+
if self.userCfg['extensions'].has_section(bindings_section):
485+
event_names |= set(
486+
self.userCfg['extensions'].GetOptionList(bindings_section)
487+
)
488+
if self.defaultCfg['extensions'].has_section(bindings_section):
489+
event_names |= set(
490+
self.defaultCfg['extensions'].GetOptionList(bindings_section)
491+
)
492+
493+
for event_name in event_names:
494+
event = f'<<{event_name}>>'
495+
binding = current_keyset.get(event, None)
496+
if binding is None:
497+
continue
498+
extension_keys[event] = binding
499+
return extension_keys
500+
501+
def __GetRawExtensionKeys(self, extension_name):
491502
"""Return dict {configurable extensionName event : keybinding list}.
492503
493504
Events come from default config extension_cfgBindings section.
494505
Keybindings list come from the splitting of GetOption, which
495506
tries user config before default config.
496507
"""
497-
keysName = extensionName+'_cfgBindings'
498-
extKeys = {}
499-
if self.defaultCfg['extensions'].has_section(keysName):
500-
eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
501-
for eventName in eventNames:
502-
binding = self.GetOption(
503-
'extensions', keysName, eventName, default='').split()
504-
event = '<<' + eventName + '>>'
505-
extKeys[event] = binding
506-
return extKeys
508+
bindings_section = f'{extension_name}_cfgBindings'
509+
extension_keys = {}
510+
511+
event_names = set()
512+
if self.userCfg['extensions'].has_section(bindings_section):
513+
event_names |= set(
514+
self.userCfg['extensions'].GetOptionList(bindings_section)
515+
)
516+
if self.defaultCfg['extensions'].has_section(bindings_section):
517+
event_names |= set(
518+
self.defaultCfg['extensions'].GetOptionList(bindings_section)
519+
)
520+
521+
for event_name in event_names:
522+
binding = self.GetOption(
523+
'extensions',
524+
bindings_section,
525+
event_name,
526+
default='',
527+
).split()
528+
event = f'<<{event_name}>>'
529+
extension_keys[event] = binding
530+
return extension_keys
507531

508532
def GetExtensionBindings(self, extensionName):
509533
"""Return dict {extensionName event : active or defined keybinding}.
@@ -512,18 +536,30 @@ def GetExtensionBindings(self, extensionName):
512536
configurable events (from default config) to GetOption splits,
513537
as in self.__GetRawExtensionKeys.
514538
"""
515-
bindsName = extensionName + '_bindings'
516-
extBinds = self.GetExtensionKeys(extensionName)
517-
#add the non-configurable bindings
518-
if self.defaultCfg['extensions'].has_section(bindsName):
519-
eventNames = self.defaultCfg['extensions'].GetOptionList(bindsName)
520-
for eventName in eventNames:
521-
binding = self.GetOption(
522-
'extensions', bindsName, eventName, default='').split()
523-
event = '<<' + eventName + '>>'
524-
extBinds[event] = binding
525-
526-
return extBinds
539+
bindings_section = f'{extensionName}_bindings'
540+
extension_keys = self.GetExtensionKeys(extensionName)
541+
542+
# add the non-configurable bindings
543+
event_names = set()
544+
if self.userCfg['extensions'].has_section(bindings_section):
545+
event_names |= set(
546+
self.userCfg['extensions'].GetOptionList(bindings_section)
547+
)
548+
if self.defaultCfg['extensions'].has_section(bindings_section):
549+
event_names |= set(
550+
self.defaultCfg['extensions'].GetOptionList(bindings_section)
551+
)
552+
553+
for event_name in event_names:
554+
binding = self.GetOption(
555+
'extensions',
556+
bindings_section,
557+
event_name,
558+
default=''
559+
).split()
560+
event = f'<<{event_name}>>'
561+
extension_keys[event] = binding
562+
return extension_keys
527563

528564
def GetKeyBinding(self, keySetName, eventStr):
529565
"""Return the keybinding list for keySetName eventStr.

Lib/idlelib/configdialog.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,12 +1960,15 @@ def create_page_extensions(self):
19601960
def load_extensions(self):
19611961
"Fill self.extensions with data from the default and user configs."
19621962
self.extensions = {}
1963+
19631964
for ext_name in idleConf.GetExtensions(active_only=False):
19641965
# Former built-in extensions are already filtered out.
19651966
self.extensions[ext_name] = []
19661967

19671968
for ext_name in self.extensions:
1968-
opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
1969+
default = set(self.ext_defaultCfg.GetOptionList(ext_name))
1970+
user = set(self.ext_userCfg.GetOptionList(ext_name))
1971+
opt_list = sorted(default | user)
19691972

19701973
# Bring 'enable' options to the beginning of the list.
19711974
enables = [opt_name for opt_name in opt_list
@@ -1975,8 +1978,12 @@ def load_extensions(self):
19751978
opt_list = enables + opt_list
19761979

19771980
for opt_name in opt_list:
1978-
def_str = self.ext_defaultCfg.Get(
1979-
ext_name, opt_name, raw=True)
1981+
if opt_name in default:
1982+
def_str = self.ext_defaultCfg.Get(
1983+
ext_name, opt_name, raw=True)
1984+
else:
1985+
def_str = self.ext_userCfg.Get(
1986+
ext_name, opt_name, raw=True)
19801987
try:
19811988
def_obj = {'True':True, 'False':False}[def_str]
19821989
opt_type = 'bool'
@@ -2054,10 +2061,11 @@ def set_extension_value(self, section, opt):
20542061
default = opt['default']
20552062
value = opt['var'].get().strip() or default
20562063
opt['var'].set(value)
2057-
# if self.defaultCfg.has_section(section):
2058-
# Currently, always true; if not, indent to return.
2059-
if (value == default):
2064+
2065+
# Only save option in user config if it differs from the default
2066+
if self.ext_defaultCfg.has_section(section) and value == default:
20602067
return self.ext_userCfg.RemoveOption(section, name)
2068+
20612069
# Set the option.
20622070
return self.ext_userCfg.SetOption(section, name, value)
20632071

Lib/idlelib/editor.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ def __init__(self, flist=None, filename=None, key=None, root=None):
312312
else:
313313
self.update_menu_state('options', '*ine*umbers', 'disabled')
314314

315+
self.mtime = self.last_mtime()
316+
text_frame.bind('<FocusIn>', self.focus_in_event)
317+
315318
def handle_winconfig(self, event=None):
316319
self.set_width()
317320

@@ -857,9 +860,8 @@ def RemoveKeybindings(self):
857860
self.text.event_delete(event, *keylist)
858861
for extensionName in self.get_standard_extension_names():
859862
xkeydefs = idleConf.GetExtensionBindings(extensionName)
860-
if xkeydefs:
861-
for event, keylist in xkeydefs.items():
862-
self.text.event_delete(event, *keylist)
863+
for event, keylist in xkeydefs.items():
864+
self.text.event_delete(event, *keylist)
863865

864866
def ApplyKeybindings(self):
865867
"""Apply the virtual, configurable keybindings.
@@ -1027,6 +1029,8 @@ def get_saved(self):
10271029

10281030
def set_saved(self, flag):
10291031
self.undo.set_saved(flag)
1032+
if flag:
1033+
self.mtime = self.last_mtime()
10301034

10311035
def reset_undo(self):
10321036
self.undo.reset_undo()
@@ -1112,6 +1116,21 @@ def _close(self):
11121116
# unless override: unregister from flist, terminate if last window
11131117
self.close_hook()
11141118

1119+
def last_mtime(self):
1120+
file = self.io.filename
1121+
return os.path.getmtime(file) if file else 0
1122+
1123+
def focus_in_event(self, event):
1124+
mtime = self.last_mtime()
1125+
if self.mtime != mtime:
1126+
self.mtime = mtime
1127+
if self. askyesno(
1128+
'Reload', '"%s"\n\nThis script has been modified by another program.'
1129+
'\nDo you want to reload it?' % self.io.filename, parent=self.text):
1130+
self.io.loadfile(self.io.filename)
1131+
else:
1132+
self.set_saved(False)
1133+
11151134
def load_extensions(self):
11161135
self.extensions = {}
11171136
self.load_standard_extensions()

0 commit comments

Comments
 (0)