Skip to content

Commit b823218

Browse files
authored
Merge pull request #383 from python/master
Sync Fork from Upstream Repo
2 parents 248f818 + 749d40a commit b823218

34 files changed

+4873
-4455
lines changed

Doc/library/functions.rst

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,8 @@ are always available. They are listed here in alphabetical order.
526526
occurs). [#]_ If it is a code object, it is simply executed. In all cases,
527527
the code that's executed is expected to be valid as file input (see the
528528
section "File input" in the Reference Manual). Be aware that the
529-
:keyword:`return` and :keyword:`yield` statements may not be used outside of
529+
:keyword:`nonlocal`, :keyword:`yield`, and :keyword:`return`
530+
statements may not be used outside of
530531
function definitions even within the context of code passed to the
531532
:func:`exec` function. The return value is ``None``.
532533

@@ -869,19 +870,27 @@ are always available. They are listed here in alphabetical order.
869870
class>`) subclass thereof. If *object* is not
870871
an object of the given type, the function always returns ``False``.
871872
If *classinfo* is a tuple of type objects (or recursively, other such
872-
tuples), return ``True`` if *object* is an instance of any of the types.
873+
tuples) or a :ref:`types-union` of multiple types, return ``True`` if
874+
*object* is an instance of any of the types.
873875
If *classinfo* is not a type or tuple of types and such tuples,
874876
a :exc:`TypeError` exception is raised.
875877

878+
.. versionchanged:: 3.10
879+
*classinfo* can be a :ref:`types-union`.
880+
876881

877882
.. function:: issubclass(class, classinfo)
878883

879884
Return ``True`` if *class* is a subclass (direct, indirect or :term:`virtual
880885
<abstract base class>`) of *classinfo*. A
881886
class is considered a subclass of itself. *classinfo* may be a tuple of class
882-
objects, in which case every entry in *classinfo* will be checked. In any other
887+
objects or a :ref:`types-union`, in which case every entry in *classinfo*
888+
will be checked. In any other
883889
case, a :exc:`TypeError` exception is raised.
884890

891+
.. versionchanged:: 3.10
892+
*classinfo* can be a :ref:`types-union`.
893+
885894

886895
.. function:: iter(object[, sentinel])
887896

Doc/library/statistics.rst

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,14 @@ However, for reading convenience, most of the examples show sorted sequences.
162162
real-valued numbers. If *weights* is omitted or *None*, then
163163
equal weighting is assumed.
164164

165-
The harmonic mean, sometimes called the subcontrary mean, is the
166-
reciprocal of the arithmetic :func:`mean` of the reciprocals of the
167-
data. For example, the harmonic mean of three values *a*, *b* and *c*
168-
will be equivalent to ``3/(1/a + 1/b + 1/c)``. If one of the values
169-
is zero, the result will be zero.
165+
The harmonic mean is the reciprocal of the arithmetic :func:`mean` of the
166+
reciprocals of the data. For example, the harmonic mean of three values *a*,
167+
*b* and *c* will be equivalent to ``3/(1/a + 1/b + 1/c)``. If one of the
168+
values is zero, the result will be zero.
170169

171170
The harmonic mean is a type of average, a measure of the central
172171
location of the data. It is often appropriate when averaging
173-
rates or ratios, for example speeds.
172+
ratios or rates, for example speeds.
174173

175174
Suppose a car travels 10 km at 40 km/hr, then another 10 km at 60 km/hr.
176175
What is the average speed?

Doc/library/stdtypes.rst

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5022,8 +5022,10 @@ enables cleaner type hinting syntax compared to :data:`typing.Union`.
50225022
str | None == typing.Optional[str]
50235023

50245024
.. describe:: isinstance(obj, union_object)
5025+
.. describe:: issubclass(obj, union_object)
50255026

5026-
Calls to :func:`isinstance` are also supported with a union object::
5027+
Calls to :func:`isinstance` and :func:`issubclass` are also supported with a
5028+
union object::
50275029

50285030
>>> isinstance("", int | str)
50295031
True
@@ -5036,21 +5038,6 @@ enables cleaner type hinting syntax compared to :data:`typing.Union`.
50365038
File "<stdin>", line 1, in <module>
50375039
TypeError: isinstance() argument 2 cannot contain a parameterized generic
50385040

5039-
.. describe:: issubclass(obj, union_object)
5040-
5041-
Calls to :func:`issubclass` are also supported with a union object::
5042-
5043-
>>> issubclass(bool, int | str)
5044-
True
5045-
5046-
However, union objects containing :ref:`parameterized generics
5047-
<types-genericalias>` cannot be used::
5048-
5049-
>>> issubclass(bool, bool | list[str])
5050-
Traceback (most recent call last):
5051-
File "<stdin>", line 1, in <module>
5052-
TypeError: issubclass() argument 2 cannot contain a parameterized generic
5053-
50545041
The user-exposed type for the union object can be accessed from
50555042
:data:`types.Union` and used for :func:`isinstance` checks. An object cannot be
50565043
instantiated from the type::

Doc/library/typing.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,8 @@ Introspection helpers
19501950
``list[ForwardRef("SomeClass")]``. This class should not be instantiated by
19511951
a user, but may be used by introspection tools.
19521952

1953+
.. versionadded:: 3.7.4
1954+
19531955
Constant
19541956
--------
19551957

Doc/whatsnew/3.10.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,13 @@ Type hints can now be written in a more succinct manner::
193193
return number ** 2
194194

195195

196-
See :pep:`604` for more details.
196+
This new syntax is also accepted as the second argument to :func:`isinstance`
197+
and :func:`issubclass`::
198+
199+
>>> isinstance(1, int | str)
200+
True
201+
202+
See :ref:`types-union` and :pep:`604` for more details.
197203

198204
(Contributed by Maggie Moss and Philippe Prados in :issue:`41428`.)
199205

@@ -638,7 +644,7 @@ Deprecated
638644
* The undocumented built-in function ``sqlite3.enable_shared_cache`` is now
639645
deprecated, scheduled for removal in Python 3.12. Its use is strongly
640646
discouraged by the SQLite3 documentation. See `the SQLite3 docs
641-
<https://sqlite.org/c3ref/enable_shared_cache.html/>`_ for more details.
647+
<https://sqlite.org/c3ref/enable_shared_cache.html>`_ for more details.
642648
If shared cache must be used, open the database in URI mode using the
643649
``cache=shared`` query parameter.
644650
(Contributed by Erlend E. Aasland in :issue:`24464`.)

Grammar/python.gram

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,10 @@ try_stmt[stmt_ty]:
201201
| 'try' &&':' b=block f=finally_block { _Py_Try(b, NULL, NULL, f, EXTRA) }
202202
| 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_block+ el=[else_block] f=[finally_block] { _Py_Try(b, ex, el, f, EXTRA) }
203203
except_block[excepthandler_ty]:
204-
| 'except' e=expression t=['as' z=NAME { z }] &&':' b=block {
204+
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
205205
_Py_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
206-
| 'except' &&':' b=block { _Py_ExceptHandler(NULL, NULL, b, EXTRA) }
206+
| 'except' ':' b=block { _Py_ExceptHandler(NULL, NULL, b, EXTRA) }
207+
| invalid_except_block
207208
finally_block[asdl_stmt_seq*]: 'finally' ':' a=block { a }
208209

209210
return_stmt[stmt_ty]:
@@ -737,3 +738,9 @@ invalid_import_from_targets:
737738
invalid_with_stmt:
738739
| [ASYNC] 'with' ','.(expression ['as' star_target])+ &&':'
739740
| [ASYNC] 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' &&':'
741+
742+
invalid_except_block:
743+
| 'except' a=expression ',' expressions ['as' NAME ] ':' {
744+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "exception group must be parenthesized") }
745+
| 'except' expression ['as' NAME ] &&':'
746+
| 'except' &&':'

Include/pyport.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ typedef int Py_ssize_clean_t;
180180
*/
181181

182182
#if defined(_MSC_VER)
183-
# if defined(PY_LOCAL_AGGRESSIVE)
184-
/* enable more aggressive optimization for visual studio */
185-
# pragma optimize("agtw", on)
183+
# if defined(PY_LOCAL_AGGRESSIVE) && !defined(Py_DEBUG)
184+
/* enable more aggressive optimization for MSVC */
185+
# pragma optimize("gt", on)
186186
#endif
187187
/* ignore warnings if the compiler decides not to inline a function */
188188
# pragma warning(disable: 4710)

Lib/codeop.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,20 @@ def _maybe_compile(compiler, source, filename, symbol):
102102
try:
103103
if code:
104104
return code
105-
if not code1 and repr(err1) == repr(err2):
105+
if not code1 and _is_syntax_error(err1, err2):
106106
raise err1
107107
finally:
108108
err1 = err2 = None
109109

110+
def _is_syntax_error(err1, err2):
111+
rep1 = repr(err1)
112+
rep2 = repr(err2)
113+
if "was never closed" in rep1 and "was never closed" in rep2:
114+
return False
115+
if rep1 == rep2:
116+
return True
117+
return False
118+
110119
def _compile(source, filename, symbol):
111120
return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT)
112121

Lib/compileall.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,14 @@ def compile_dir(dir, maxlevels=None, ddir=None, force=False,
8484
if workers < 0:
8585
raise ValueError('workers must be greater or equal to 0')
8686
if workers != 1:
87+
# Check if this is a system where ProcessPoolExecutor can function.
88+
from concurrent.futures.process import _check_system_limits
8789
try:
88-
# Only import when needed, as low resource platforms may
89-
# fail to import it
90-
from concurrent.futures import ProcessPoolExecutor
91-
except ImportError:
90+
_check_system_limits()
91+
except NotImplementedError:
9292
workers = 1
93+
else:
94+
from concurrent.futures import ProcessPoolExecutor
9395
if maxlevels is None:
9496
maxlevels = sys.getrecursionlimit()
9597
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels)

Lib/concurrent/futures/process.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,14 @@ def _check_system_limits():
532532
if _system_limited:
533533
raise NotImplementedError(_system_limited)
534534
_system_limits_checked = True
535+
try:
536+
import multiprocessing.synchronize
537+
except ImportError:
538+
_system_limited = (
539+
"This Python build lacks multiprocessing.synchronize, usually due "
540+
"to named semaphores being unavailable on this platform."
541+
)
542+
raise NotImplementedError(_system_limited)
535543
try:
536544
nsems_max = os.sysconf("SC_SEM_NSEMS_MAX")
537545
except (AttributeError, ValueError):

Lib/enum.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,28 +139,38 @@ def __get__(self, instance, ownerclass=None):
139139
return ownerclass._member_map_[self.name]
140140
except KeyError:
141141
raise AttributeError(
142-
'%s: no attribute %r' % (ownerclass.__name__, self.name)
142+
'%s: no class attribute %r' % (ownerclass.__name__, self.name)
143143
)
144144
else:
145145
if self.fget is None:
146+
# check for member
147+
if self.name in ownerclass._member_map_:
148+
import warnings
149+
warnings.warn(
150+
"accessing one member from another is not supported, "
151+
" and will be disabled in 3.11",
152+
DeprecationWarning,
153+
stacklevel=2,
154+
)
155+
return ownerclass._member_map_[self.name]
146156
raise AttributeError(
147-
'%s: no attribute %r' % (ownerclass.__name__, self.name)
157+
'%s: no instance attribute %r' % (ownerclass.__name__, self.name)
148158
)
149159
else:
150160
return self.fget(instance)
151161

152162
def __set__(self, instance, value):
153163
if self.fset is None:
154164
raise AttributeError(
155-
"%s: cannot set attribute %r" % (self.clsname, self.name)
165+
"%s: cannot set instance attribute %r" % (self.clsname, self.name)
156166
)
157167
else:
158168
return self.fset(instance, value)
159169

160170
def __delete__(self, instance):
161171
if self.fdel is None:
162172
raise AttributeError(
163-
"%s: cannot delete attribute %r" % (self.clsname, self.name)
173+
"%s: cannot delete instance attribute %r" % (self.clsname, self.name)
164174
)
165175
else:
166176
return self.fdel(instance)

Lib/multiprocessing/resource_tracker.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,16 @@
3737
import _multiprocessing
3838
import _posixshmem
3939

40+
# Use sem_unlink() to clean up named semaphores.
41+
#
42+
# sem_unlink() may be missing if the Python build process detected the
43+
# absence of POSIX named semaphores. In that case, no named semaphores were
44+
# ever opened, so no cleanup would be necessary.
45+
if hasattr(_multiprocessing, 'sem_unlink'):
46+
_CLEANUP_FUNCS.update({
47+
'semaphore': _multiprocessing.sem_unlink,
48+
})
4049
_CLEANUP_FUNCS.update({
41-
'semaphore': _multiprocessing.sem_unlink,
4250
'shared_memory': _posixshmem.shm_unlink,
4351
})
4452

Lib/statistics.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,9 @@ def geometric_mean(data):
367367
def harmonic_mean(data, weights=None):
368368
"""Return the harmonic mean of data.
369369
370-
The harmonic mean, sometimes called the subcontrary mean, is the
371-
reciprocal of the arithmetic mean of the reciprocals of the data,
372-
and is often appropriate when averaging quantities which are rates
373-
or ratios, for example speeds.
370+
The harmonic mean is the reciprocal of the arithmetic mean of the
371+
reciprocals of the data. It can be used for averaging ratios or
372+
rates, for example speeds.
374373
375374
Suppose a car travels 40 km/hr for 5 km and then speeds-up to
376375
60 km/hr for another 5 km. What is the average speed?

Lib/test/test_codeop.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ def test_incomplete(self):
135135
ai("a = {")
136136
ai("b + {")
137137

138+
ai("print([1,\n2,")
139+
ai("print({1:1,\n2:3,")
140+
ai("print((1,\n2,")
141+
138142
ai("if 9==3:\n pass\nelse:")
139143
ai("if 9==3:\n pass\nelse:\n")
140144
ai("if 9==3:\n pass\nelse:\n pass")

Lib/test/test_compile.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,17 @@ def check_same_constant(const):
632632
self.check_constant(f1, frozenset({0}))
633633
self.assertTrue(f1(0))
634634

635+
# Merging equal co_linetable and co_code is not a strict requirement
636+
# for the Python semantics, it's a more an implementation detail.
637+
@support.cpython_only
638+
def test_merge_code_attrs(self):
639+
# See https://bugs.python.org/issue42217
640+
f1 = lambda x: x.y.z
641+
f2 = lambda a: a.b.c
642+
643+
self.assertIs(f1.__code__.co_linetable, f2.__code__.co_linetable)
644+
self.assertIs(f1.__code__.co_code, f2.__code__.co_code)
645+
635646
# This is a regression test for a CPython specific peephole optimizer
636647
# implementation bug present in a few releases. It's assertion verifies
637648
# that peephole optimization was actually done though that isn't an

Lib/test/test_compileall.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616
import unittest
1717

1818
from unittest import mock, skipUnless
19+
from concurrent.futures import ProcessPoolExecutor
1920
try:
20-
from concurrent.futures import ProcessPoolExecutor
21+
# compileall relies on ProcessPoolExecutor if ProcessPoolExecutor exists
22+
# and it can function.
23+
from concurrent.futures.process import _check_system_limits
24+
_check_system_limits()
2125
_have_multiprocessing = True
22-
except ImportError:
26+
except NotImplementedError:
2327
_have_multiprocessing = False
2428

2529
from test import support
@@ -188,6 +192,7 @@ def test_compile_dir_pathlike(self):
188192
self.assertRegex(line, r'Listing ([^WindowsPath|PosixPath].*)')
189193
self.assertTrue(os.path.isfile(self.bc_path))
190194

195+
@skipUnless(_have_multiprocessing, "requires multiprocessing")
191196
@mock.patch('concurrent.futures.ProcessPoolExecutor')
192197
def test_compile_pool_called(self, pool_mock):
193198
compileall.compile_dir(self.directory, quiet=True, workers=5)
@@ -198,11 +203,13 @@ def test_compile_workers_non_positive(self):
198203
"workers must be greater or equal to 0"):
199204
compileall.compile_dir(self.directory, workers=-1)
200205

206+
@skipUnless(_have_multiprocessing, "requires multiprocessing")
201207
@mock.patch('concurrent.futures.ProcessPoolExecutor')
202208
def test_compile_workers_cpu_count(self, pool_mock):
203209
compileall.compile_dir(self.directory, quiet=True, workers=0)
204210
self.assertEqual(pool_mock.call_args[1]['max_workers'], None)
205211

212+
@skipUnless(_have_multiprocessing, "requires multiprocessing")
206213
@mock.patch('concurrent.futures.ProcessPoolExecutor')
207214
@mock.patch('compileall.compile_file')
208215
def test_compile_one_worker(self, compile_file_mock, pool_mock):

0 commit comments

Comments
 (0)