Skip to content

Commit 86a6dbc

Browse files
Merge branch 'main' into isolate-io/1-heap-types
2 parents 39e0a89 + 0729359 commit 86a6dbc

Some content is hidden

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

44 files changed

+444
-182
lines changed

Doc/c-api/function.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ There are a few functions specific to Python functions.
169169
before the modification to *func* takes place, so the prior state of *func*
170170
can be inspected. The runtime is permitted to optimize away the creation of
171171
function objects when possible. In such cases no event will be emitted.
172-
Although this creates the possitibility of an observable difference of
172+
Although this creates the possibility of an observable difference of
173173
runtime behavior depending on optimization decisions, it does not change
174174
the semantics of the Python code being executed.
175175

Doc/c-api/module.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -388,15 +388,15 @@ objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and
388388
389389
.. c:function:: PyObject * PyModule_FromDefAndSpec(PyModuleDef *def, PyObject *spec)
390390
391-
Create a new module object, given the definition in *module* and the
391+
Create a new module object, given the definition in *def* and the
392392
ModuleSpec *spec*. This behaves like :c:func:`PyModule_FromDefAndSpec2`
393393
with *module_api_version* set to :const:`PYTHON_API_VERSION`.
394394
395395
.. versionadded:: 3.5
396396
397397
.. c:function:: PyObject * PyModule_FromDefAndSpec2(PyModuleDef *def, PyObject *spec, int module_api_version)
398398
399-
Create a new module object, given the definition in *module* and the
399+
Create a new module object, given the definition in *def* and the
400400
ModuleSpec *spec*, assuming the API version *module_api_version*.
401401
If that version does not match the version of the running interpreter,
402402
a :exc:`RuntimeWarning` is emitted.

Doc/library/argparse.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1867,7 +1867,7 @@ Sub-commands
18671867
...
18681868
>>> # create the top-level parser
18691869
>>> parser = argparse.ArgumentParser()
1870-
>>> subparsers = parser.add_subparsers()
1870+
>>> subparsers = parser.add_subparsers(required=True)
18711871
>>>
18721872
>>> # create the parser for the "foo" command
18731873
>>> parser_foo = subparsers.add_parser('foo')

Doc/library/asyncio-stream.rst

+10-2
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,20 @@ StreamReader
206206

207207
.. coroutinemethod:: read(n=-1)
208208

209-
Read up to *n* bytes. If *n* is not provided, or set to ``-1``,
210-
read until EOF and return all read bytes.
209+
Read up to *n* bytes from the stream.
211210

211+
If *n* is not provided or set to ``-1``,
212+
read until EOF, then return all read :class:`bytes`.
212213
If EOF was received and the internal buffer is empty,
213214
return an empty ``bytes`` object.
214215

216+
If *n* is ``0``, return an empty ``bytes`` object immediately.
217+
218+
If *n* is positive, return at most *n* available ``bytes``
219+
as soon as at least 1 byte is available in the internal buffer.
220+
If EOF is received before any byte is read, return an empty
221+
``bytes`` object.
222+
215223
.. coroutinemethod:: readline()
216224

217225
Read one line, where "line" is a sequence of bytes

Doc/library/csv.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ Reader objects have the following public attributes:
458458

459459
DictReader objects have the following public attribute:
460460

461-
.. attribute:: csvreader.fieldnames
461+
.. attribute:: DictReader.fieldnames
462462

463463
If not passed as a parameter when creating the object, this attribute is
464464
initialized upon first access or when the first record is read from the

Doc/library/enum.rst

+8-9
Original file line numberDiff line numberDiff line change
@@ -696,10 +696,9 @@ Data Types
696696

697697
.. attribute:: STRICT
698698

699-
Out-of-range values cause a :exc:`ValueError` to be raised. This is the
700-
default for :class:`Flag`::
699+
Out-of-range values cause a :exc:`ValueError` to be raised::
701700

702-
>>> from enum import Flag, STRICT
701+
>>> from enum import Flag, STRICT, auto
703702
>>> class StrictFlag(Flag, boundary=STRICT):
704703
... RED = auto()
705704
... GREEN = auto()
@@ -715,9 +714,9 @@ Data Types
715714
.. attribute:: CONFORM
716715

717716
Out-of-range values have invalid values removed, leaving a valid *Flag*
718-
value::
717+
value. This is the default for :class:`Flag`::
719718

720-
>>> from enum import Flag, CONFORM
719+
>>> from enum import Flag, CONFORM, auto
721720
>>> class ConformFlag(Flag, boundary=CONFORM):
722721
... RED = auto()
723722
... GREEN = auto()
@@ -731,7 +730,7 @@ Data Types
731730
Out-of-range values lose their *Flag* membership and revert to :class:`int`.
732731
This is the default for :class:`IntFlag`::
733732

734-
>>> from enum import Flag, EJECT
733+
>>> from enum import Flag, EJECT, auto
735734
>>> class EjectFlag(Flag, boundary=EJECT):
736735
... RED = auto()
737736
... GREEN = auto()
@@ -742,10 +741,10 @@ Data Types
742741

743742
.. attribute:: KEEP
744743

745-
Out-of-range values are kept, and the *Flag* membership is kept. This is
746-
used for some stdlib flags:
744+
Out-of-range values are kept, and the *Flag* membership is kept. This is
745+
used for some stdlib flags::
747746

748-
>>> from enum import Flag, KEEP
747+
>>> from enum import Flag, KEEP, auto
749748
>>> class KeepFlag(Flag, boundary=KEEP):
750749
... RED = auto()
751750
... GREEN = auto()

Doc/library/functions.rst

+3
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,9 @@ are always available. They are listed here in alphabetical order.
16351635
example: ``a[start:stop:step]`` or ``a[start:stop, i]``. See
16361636
:func:`itertools.islice` for an alternate version that returns an iterator.
16371637

1638+
.. versionchanged:: 3.12
1639+
Slice objects are now :term:`hashable` (provided :attr:`~slice.start`,
1640+
:attr:`~slice.stop`, and :attr:`~slice.step` are hashable).
16381641

16391642
.. function:: sorted(iterable, /, *, key=None, reverse=False)
16401643

Doc/library/plistlib.rst

+15-6
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ Examples
159159

160160
Generating a plist::
161161

162+
import datetime
163+
import plistlib
164+
162165
pl = dict(
163166
aString = "Doodah",
164167
aList = ["A", "B", 12, 32.1, [1, 2, 3]],
@@ -172,13 +175,19 @@ Generating a plist::
172175
),
173176
someData = b"<binary gunk>",
174177
someMoreData = b"<lots of binary gunk>" * 10,
175-
aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())),
178+
aDate = datetime.datetime.now()
176179
)
177-
with open(fileName, 'wb') as fp:
178-
dump(pl, fp)
180+
print(plistlib.dumps(pl).decode())
179181

180182
Parsing a plist::
181183

182-
with open(fileName, 'rb') as fp:
183-
pl = load(fp)
184-
print(pl["aKey"])
184+
import plistlib
185+
186+
plist = b"""<plist version="1.0">
187+
<dict>
188+
<key>foo</key>
189+
<string>bar</string>
190+
</dict>
191+
</plist>"""
192+
pl = plistlib.loads(plist)
193+
print(pl["foo"])

Doc/library/urllib.error.rst

+12-1
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,19 @@ The following exceptions are raised by :mod:`urllib.error` as appropriate:
3131
of :exc:`IOError`.
3232

3333

34-
.. exception:: HTTPError
34+
.. exception:: HTTPError(url, code, msg, hdrs, fp)
3535

3636
Though being an exception (a subclass of :exc:`URLError`), an
3737
:exc:`HTTPError` can also function as a non-exceptional file-like return
3838
value (the same thing that :func:`~urllib.request.urlopen` returns). This
3939
is useful when handling exotic HTTP errors, such as requests for
4040
authentication.
4141

42+
.. attribute:: url
43+
44+
Contains the request URL.
45+
An alias for *filename* attribute.
46+
4247
.. attribute:: code
4348

4449
An HTTP status code as defined in :rfc:`2616`. This numeric value corresponds
@@ -48,14 +53,20 @@ The following exceptions are raised by :mod:`urllib.error` as appropriate:
4853
.. attribute:: reason
4954

5055
This is usually a string explaining the reason for this error.
56+
An alias for *msg* attribute.
5157

5258
.. attribute:: headers
5359

5460
The HTTP response headers for the HTTP request that caused the
5561
:exc:`HTTPError`.
62+
An alias for *hdrs* attribute.
5663

5764
.. versionadded:: 3.4
5865

66+
.. attribute:: fp
67+
68+
A file-like object where the HTTP error body can be read from.
69+
5970
.. exception:: ContentTooShortError(msg, content)
6071

6172
This exception is raised when the :func:`~urllib.request.urlretrieve`

Lib/asyncio/streams.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -649,16 +649,17 @@ async def readuntil(self, separator=b'\n'):
649649
async def read(self, n=-1):
650650
"""Read up to `n` bytes from the stream.
651651
652-
If n is not provided, or set to -1, read until EOF and return all read
653-
bytes. If the EOF was received and the internal buffer is empty, return
654-
an empty bytes object.
652+
If `n` is not provided or set to -1,
653+
read until EOF, then return all read bytes.
654+
If EOF was received and the internal buffer is empty,
655+
return an empty bytes object.
655656
656-
If n is zero, return empty bytes object immediately.
657+
If `n` is 0, return an empty bytes object immediately.
657658
658-
If n is positive, this function try to read `n` bytes, and may return
659-
less or equal bytes than requested, but at least one byte. If EOF was
660-
received before any byte is read, this function returns empty byte
661-
object.
659+
If `n` is positive, return at most `n` available bytes
660+
as soon as at least 1 byte is available in the internal buffer.
661+
If EOF is received before any byte is read, return an empty
662+
bytes object.
662663
663664
Returned value is not limited with limit, configured at stream
664665
creation.

Lib/importlib/resources/_adapters.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ def _io_wrapper(file, mode='r', *args, **kwargs):
3434
return TextIOWrapper(file, *args, **kwargs)
3535
elif mode == 'rb':
3636
return file
37-
raise ValueError(
38-
f"Invalid mode value '{mode}', only 'r' and 'rb' are supported"
39-
)
37+
raise ValueError(f"Invalid mode value '{mode}', only 'r' and 'rb' are supported")
4038

4139

4240
class CompatibilityFiles:

Lib/importlib/resources/_itertools.py

+36-33
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,38 @@
1-
from itertools import filterfalse
1+
# from more_itertools 9.0
2+
def only(iterable, default=None, too_long=None):
3+
"""If *iterable* has only one item, return it.
4+
If it has zero items, return *default*.
5+
If it has more than one item, raise the exception given by *too_long*,
6+
which is ``ValueError`` by default.
7+
>>> only([], default='missing')
8+
'missing'
9+
>>> only([1])
10+
1
11+
>>> only([1, 2]) # doctest: +IGNORE_EXCEPTION_DETAIL
12+
Traceback (most recent call last):
13+
...
14+
ValueError: Expected exactly one item in iterable, but got 1, 2,
15+
and perhaps more.'
16+
>>> only([1, 2], too_long=TypeError) # doctest: +IGNORE_EXCEPTION_DETAIL
17+
Traceback (most recent call last):
18+
...
19+
TypeError
20+
Note that :func:`only` attempts to advance *iterable* twice to ensure there
21+
is only one item. See :func:`spy` or :func:`peekable` to check
22+
iterable contents less destructively.
23+
"""
24+
it = iter(iterable)
25+
first_value = next(it, default)
226

3-
from typing import (
4-
Callable,
5-
Iterable,
6-
Iterator,
7-
Optional,
8-
Set,
9-
TypeVar,
10-
Union,
11-
)
12-
13-
# Type and type variable definitions
14-
_T = TypeVar('_T')
15-
_U = TypeVar('_U')
16-
17-
18-
def unique_everseen(
19-
iterable: Iterable[_T], key: Optional[Callable[[_T], _U]] = None
20-
) -> Iterator[_T]:
21-
"List unique elements, preserving order. Remember all elements ever seen."
22-
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
23-
# unique_everseen('ABBCcAD', str.lower) --> A B C D
24-
seen: Set[Union[_T, _U]] = set()
25-
seen_add = seen.add
26-
if key is None:
27-
for element in filterfalse(seen.__contains__, iterable):
28-
seen_add(element)
29-
yield element
27+
try:
28+
second_value = next(it)
29+
except StopIteration:
30+
pass
3031
else:
31-
for element in iterable:
32-
k = key(element)
33-
if k not in seen:
34-
seen_add(k)
35-
yield element
32+
msg = (
33+
'Expected exactly one item in iterable, but got {!r}, {!r}, '
34+
'and perhaps more.'.format(first_value, second_value)
35+
)
36+
raise too_long or ValueError(msg)
37+
38+
return first_value

Lib/importlib/resources/readers.py

+30-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import collections
2-
import operator
2+
import itertools
33
import pathlib
4+
import operator
45
import zipfile
56

67
from . import abc
78

8-
from ._itertools import unique_everseen
9+
from ._itertools import only
910

1011

1112
def remove_duplicates(items):
@@ -41,8 +42,10 @@ def open_resource(self, resource):
4142
raise FileNotFoundError(exc.args[0])
4243

4344
def is_resource(self, path):
44-
# workaround for `zipfile.Path.is_file` returning true
45-
# for non-existent paths.
45+
"""
46+
Workaround for `zipfile.Path.is_file` returning true
47+
for non-existent paths.
48+
"""
4649
target = self.files().joinpath(path)
4750
return target.is_file() and target.exists()
4851

@@ -67,8 +70,10 @@ def __init__(self, *paths):
6770
raise NotADirectoryError('MultiplexedPath only supports directories')
6871

6972
def iterdir(self):
70-
files = (file for path in self._paths for file in path.iterdir())
71-
return unique_everseen(files, key=operator.attrgetter('name'))
73+
children = (child for path in self._paths for child in path.iterdir())
74+
by_name = operator.attrgetter('name')
75+
groups = itertools.groupby(sorted(children, key=by_name), key=by_name)
76+
return map(self._follow, (locs for name, locs in groups))
7277

7378
def read_bytes(self):
7479
raise FileNotFoundError(f'{self} is not a file')
@@ -90,6 +95,25 @@ def joinpath(self, *descendants):
9095
# Just return something that will not exist.
9196
return self._paths[0].joinpath(*descendants)
9297

98+
@classmethod
99+
def _follow(cls, children):
100+
"""
101+
Construct a MultiplexedPath if needed.
102+
103+
If children contains a sole element, return it.
104+
Otherwise, return a MultiplexedPath of the items.
105+
Unless one of the items is not a Directory, then return the first.
106+
"""
107+
subdirs, one_dir, one_file = itertools.tee(children, 3)
108+
109+
try:
110+
return only(one_dir)
111+
except ValueError:
112+
try:
113+
return cls(*subdirs)
114+
except NotADirectoryError:
115+
return next(one_file)
116+
93117
def open(self, *args, **kwargs):
94118
raise FileNotFoundError(f'{self} is not a file')
95119

0 commit comments

Comments
 (0)