Skip to content

Commit d487864

Browse files
Merge branch 'main' into gh-145142-dict-next-critical-section
2 parents c56d358 + 4c95ad8 commit d487864

25 files changed

+313
-127
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ Programs/_bootstrap_python.c @ericsnowcurrently
289289
Programs/python.c @ericsnowcurrently
290290

291291
# JIT
292+
.github/workflows/jit.yml @savannahostrowski
292293
Include/internal/pycore_jit.h @brandtbucher @savannahostrowski @diegorusso
293294
Python/jit.c @brandtbucher @savannahostrowski @diegorusso
294295
Tools/jit/ @brandtbucher @savannahostrowski @diegorusso

Doc/library/importlib.metadata.rst

Lines changed: 102 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ Entry points
125125
:meth:`!select` method for comparison to the attributes of
126126
the individual entry point definitions.
127127

128-
Note: it is not currently possible to query for entry points based on
129-
their :attr:`!EntryPoint.dist` attribute (as different :class:`!Distribution`
128+
Note: to query for entry points based on :attr:`!EntryPoint.dist` attribute,
129+
use :meth:`Distribution.entry_points` instead (as different :class:`Distribution`
130130
instances do not currently compare equal, even if they have the same attributes)
131131

132132
.. class:: EntryPoints
@@ -291,7 +291,7 @@ Distribution files
291291
.. function:: files(distribution_name)
292292

293293
Return the full set of files contained within the named
294-
distribution package.
294+
distribution package as :class:`PackagePath` instances.
295295

296296
Raises :exc:`PackageNotFoundError` if the named distribution
297297
package is not installed in the current Python environment.
@@ -304,12 +304,22 @@ Distribution files
304304

305305
A :class:`pathlib.PurePath` derived object with additional ``dist``,
306306
``size``, and ``hash`` properties corresponding to the distribution
307-
package's installation metadata for that file.
307+
package's installation metadata for that file, also:
308+
309+
.. method:: locate()
310+
311+
If possible, return the concrete :class:`SimplePath` allowing to access data,
312+
or raise a :exc:`NotImplementedError` otherwise.
313+
314+
.. class:: SimplePath
315+
316+
A protocol representing a minimal subset of :class:`pathlib.Path` that allows to
317+
check if it ``exists()``, to traverse using ``joinpath()`` and ``parent``,
318+
and to retrieve data using ``read_text()`` and ``read_bytes()``.
308319

309320
The :func:`!files` function takes a
310321
`Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_
311-
name and returns all of the files installed by this distribution. Each file is reported
312-
as a :class:`PackagePath` instance. For example::
322+
name and returns all of the files installed by this distribution. For example::
313323

314324
>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP
315325
>>> util # doctest: +SKIP
@@ -402,6 +412,18 @@ function is not reliable with such installs.
402412
Distributions
403413
=============
404414

415+
While the module level API described above is the most common and convenient usage,
416+
all that information is accessible from the :class:`Distribution` class.
417+
:class:`!Distribution` is an abstract object that represents the metadata for
418+
a Python `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_.
419+
Get the concrete :class:`!Distribution` subclass instance for an installed
420+
distribution package by calling the :func:`distribution` function::
421+
422+
>>> from importlib.metadata import distribution # doctest: +SKIP
423+
>>> dist = distribution('wheel') # doctest: +SKIP
424+
>>> type(dist) # doctest: +SKIP
425+
<class 'importlib.metadata.PathDistribution'>
426+
405427
.. function:: distribution(distribution_name)
406428

407429
Return a :class:`Distribution` instance describing the named
@@ -410,6 +432,14 @@ Distributions
410432
Raises :exc:`PackageNotFoundError` if the named distribution
411433
package is not installed in the current Python environment.
412434

435+
Thus, an alternative way to get e.g. the version number is through the
436+
:attr:`Distribution.version` attribute::
437+
438+
>>> dist.version # doctest: +SKIP
439+
'0.32.3'
440+
441+
The same applies for :func:`entry_points` and :func:`files`.
442+
413443
.. class:: Distribution
414444

415445
Details of an installed distribution package.
@@ -418,53 +448,85 @@ Distributions
418448
equal, even if they relate to the same installed distribution and
419449
accordingly have the same attributes.
420450

421-
.. method:: discover(cls, *, context=None, **kwargs)
451+
.. staticmethod:: at(path)
452+
.. classmethod:: from_name(name)
453+
454+
Return a :class:`!Distribution` instance at the given path or
455+
with the given name.
422456

423-
Returns an iterable of :class:`Distribution` instances for all packages.
457+
.. classmethod:: discover(*, context=None, **kwargs)
458+
459+
Returns an iterable of :class:`!Distribution` instances for all packages
460+
(see distribution-discovery_).
424461

425462
The optional argument *context* is a :class:`DistributionFinder.Context`
426463
instance, used to modify the search for distributions. Alternatively,
427464
*kwargs* may contain keyword arguments for constructing a new
428465
:class:`!DistributionFinder.Context`.
429466

467+
.. attribute:: metadata
468+
:type: PackageMetadata
430469

431-
While the module level API described above is the most common and convenient usage,
432-
you can get all of that information from the :class:`!Distribution` class.
433-
:class:`!Distribution` is an abstract object that represents the metadata for
434-
a Python `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_.
435-
You can get the concrete :class:`!Distribution` subclass instance for an installed
436-
distribution package by calling the :func:`distribution` function::
470+
There are all kinds of additional metadata available on :class:`!Distribution`
471+
instances as a :class:`PackageMetadata` instance::
437472

438-
>>> from importlib.metadata import distribution # doctest: +SKIP
439-
>>> dist = distribution('wheel') # doctest: +SKIP
440-
>>> type(dist) # doctest: +SKIP
441-
<class 'importlib.metadata.PathDistribution'>
473+
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
474+
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
475+
>>> dist.metadata['License'] # doctest: +SKIP
476+
'MIT'
442477

443-
Thus, an alternative way to get the version number is through the
444-
:class:`!Distribution` instance::
478+
The full set of available metadata is not described here.
479+
See the PyPA `Core metadata specification <https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata>`_ for additional details.
445480

446-
>>> dist.version # doctest: +SKIP
447-
'0.32.3'
481+
.. attribute:: name
482+
:type: str
483+
.. attribute:: requires
484+
:type: list[str]
485+
.. attribute:: version
486+
:type: str
448487

449-
There are all kinds of additional metadata available on :class:`!Distribution`
450-
instances::
488+
A few metadata fields are also available as shortcut properties.
451489

452-
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
453-
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
454-
>>> dist.metadata['License'] # doctest: +SKIP
455-
'MIT'
490+
.. versionadded:: 3.10
456491

457-
For editable packages, an ``origin`` property may present :pep:`610`
458-
metadata::
492+
The ``name`` shortcut was added.
459493

460-
>>> dist.origin.url
461-
'file:///path/to/wheel-0.32.3.editable-py3-none-any.whl'
494+
.. attribute:: origin
462495

463-
The full set of available metadata is not described here.
464-
See the PyPA `Core metadata specification <https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata>`_ for additional details.
496+
For editable packages, an ``origin`` property may present :pep:`610`
497+
metadata (for non-editable packages, ``origin`` is :const:`None`)::
498+
499+
>>> dist.origin.url
500+
'file:///path/to/wheel-0.32.3.editable-py3-none-any.whl'
501+
502+
The ``origin`` object follows the `Direct URL Data Structure
503+
<https://packaging.python.org/en/latest/specifications/direct-url-data-structure/>`_.
504+
505+
.. versionadded:: 3.13
506+
507+
.. attribute:: entry_points
508+
:type: EntryPoints
509+
510+
The entry points provided by this distribution package.
511+
512+
.. attribute:: files
513+
:type: list[PackagePath] | None
514+
515+
All files contained in this distribution package.
516+
Like :func:`files`, this returns :const:`None` if there are no records.
517+
518+
The following two abstract methods need to be implemented when implementing-custom-providers_:
519+
520+
.. method:: locate_file(path)
521+
522+
Like :meth:`!PackagePath.locate`, return a :class:`SimplePath` for the given path.
523+
Takes a :class:`os.PathLike` or a :class:`str`.
524+
525+
.. method:: read_text(filename)
526+
527+
A shortcut for ``distribution.locate_file(filename).read_text()``.
465528

466-
.. versionadded:: 3.13
467-
The ``.origin`` property was added.
529+
.. _distribution-discovery:
468530

469531
Distribution Discovery
470532
======================
@@ -575,8 +637,8 @@ consumer.
575637

576638
In practice, to support finding distribution package
577639
metadata in locations other than the file system, subclass
578-
``Distribution`` and implement the abstract methods. Then from
579-
a custom finder, return instances of this derived ``Distribution`` in the
640+
:class:`!Distribution` and implement the abstract methods. Then from
641+
a custom finder, return instances of this derived :class:`!Distribution` in the
580642
``find_distributions()`` method.
581643

582644
Example
@@ -653,8 +715,8 @@ packages served by the ``DatabaseImporter``, assuming that the
653715
``.entry_points`` attributes.
654716

655717
The ``DatabaseDistribution`` may also provide other metadata files, like
656-
``RECORD`` (required for ``Distribution.files``) or override the
657-
implementation of ``Distribution.files``. See the source for more inspiration.
718+
``RECORD`` (required for :attr:`!Distribution.files`) or override the
719+
implementation of :attr:`!Distribution.files`. See the source for more inspiration.
658720

659721

660722
.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points

Doc/using/windows.rst

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ work.
285285
Passing ``--dry-run`` will generate output and logs, but will not modify any
286286
installs.
287287

288+
Passing ``--refresh`` will update all registrations for installed runtimes. This
289+
will recreate Start menu shortcuts, registry keys, and global aliases (such as
290+
``python3.14.exe`` or for any installed scripts). These are automatically
291+
refreshed on installation of any runtime, but may need to be manually refreshed
292+
after installing packages.
293+
288294
In addition to the above options, the ``--target`` option will extract the
289295
runtime to the specified directory instead of doing a normal install.
290296
This is useful for embedding runtimes into larger applications.
@@ -467,6 +473,14 @@ customization.
467473
- ``PYTHON_MANAGER_SOURCE_URL``
468474
- Override the index feed to obtain new installs from.
469475

476+
* - ``install.enable_entrypoints``
477+
- (none)
478+
- True to generate global commands for installed packages (such as
479+
``pip.exe``). These are defined by the packages themselves.
480+
If set to false, only the Python interpreter has global commands created.
481+
By default, true. You should run ``py install --refresh`` after changing
482+
this setting.
483+
470484
* - ``list.format``
471485
- ``PYTHON_MANAGER_LIST_FORMAT``
472486
- Specify the default format used by the ``py list`` command.
@@ -480,8 +494,8 @@ customization.
480494

481495
* - ``global_dir``
482496
- (none)
483-
- Specify the directory where global commands (such as ``python3.14.exe``)
484-
are stored.
497+
- Specify the directory where global commands (such as ``python3.14.exe``
498+
and ``pip.exe``) are stored.
485499
This directory should be added to your :envvar:`PATH` to make the
486500
commands available from your terminal.
487501

@@ -491,6 +505,7 @@ customization.
491505
This directory is a temporary cache, and can be cleaned up from time to
492506
time.
493507

508+
494509
Dotted names should be nested inside JSON objects, for example, ``list.format``
495510
would be specified as ``{"list": {"format": "table"}}``.
496511

@@ -737,6 +752,14 @@ directory containing the configuration file that specified them.
737752
(e.g. ``"pep514,start"``).
738753
Disabled shortcuts are not reactivated by ``enable_shortcut_kinds``.
739754

755+
* - ``install.hard_link_entrypoints``
756+
- True to use hard links for global shortcuts to save disk space. If false,
757+
each shortcut executable is copied instead. After changing this setting,
758+
you must run ``py install --refresh --force`` to update existing
759+
commands.
760+
By default, true. Disabling this may be necessary for troubleshooting or
761+
systems that have issues with file links.
762+
740763
* - ``pep514_root``
741764
- Registry location to read and write PEP 514 entries into.
742765
By default, :file:`HKEY_CURRENT_USER\\Software\\Python`.
@@ -876,12 +899,22 @@ default).
876899

877900
* -
878901
- The package may be available but missing the generated executable.
879-
We recommend using the ``python -m pip`` command instead,
880-
or alternatively the ``python -m pip install --force pip`` command
881-
will recreate the executables and show you the path to
882-
add to :envvar:`PATH`.
883-
These scripts are separated for each runtime, and so you may need to
884-
add multiple paths.
902+
We recommend using the ``python -m pip`` command instead.
903+
Running ``py install --refresh`` and ensuring that the global shortcuts
904+
directory is on :envvar:`PATH` (it will be shown in the command output if
905+
it is not) should make commands such as ``pip`` (and other installed
906+
packages) available.
907+
908+
* - I installed a package with ``pip`` but its command is not found.
909+
- Have you activated a virtual environment?
910+
Run the ``.venv\Scripts\activate`` script in your terminal to activate.
911+
912+
* -
913+
- New packages do not automatically have global shortcuts created by the
914+
Python install manager. Similarly, uninstalled packages do not have their
915+
shortcuts removed.
916+
Run ``py install --refresh`` to update the global shortcuts for newly
917+
installed packages.
885918

886919
* - Typing ``script-name.py`` in the terminal opens in a new window.
887920
- This is a known limitation of the operating system. Either specify ``py``

Lib/asyncio/windows_utils.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import msvcrt
1111
import os
1212
import subprocess
13-
import tempfile
1413
import warnings
1514

1615

@@ -24,17 +23,14 @@
2423
PIPE = subprocess.PIPE
2524
STDOUT = subprocess.STDOUT
2625
_mmap_counter = itertools.count()
26+
_MAX_PIPE_ATTEMPTS = 20
2727

2828

2929
# Replacement for os.pipe() using handles instead of fds
3030

3131

3232
def pipe(*, duplex=False, overlapped=(True, True), bufsize=BUFSIZE):
3333
"""Like os.pipe() but with overlapped support and using handles not fds."""
34-
address = tempfile.mktemp(
35-
prefix=r'\\.\pipe\python-pipe-{:d}-{:d}-'.format(
36-
os.getpid(), next(_mmap_counter)))
37-
3834
if duplex:
3935
openmode = _winapi.PIPE_ACCESS_DUPLEX
4036
access = _winapi.GENERIC_READ | _winapi.GENERIC_WRITE
@@ -56,9 +52,20 @@ def pipe(*, duplex=False, overlapped=(True, True), bufsize=BUFSIZE):
5652

5753
h1 = h2 = None
5854
try:
59-
h1 = _winapi.CreateNamedPipe(
60-
address, openmode, _winapi.PIPE_WAIT,
61-
1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
55+
for attempts in itertools.count():
56+
address = r'\\.\pipe\python-pipe-{:d}-{:d}-{}'.format(
57+
os.getpid(), next(_mmap_counter), os.urandom(8).hex())
58+
try:
59+
h1 = _winapi.CreateNamedPipe(
60+
address, openmode, _winapi.PIPE_WAIT,
61+
1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
62+
break
63+
except OSError as e:
64+
if attempts >= _MAX_PIPE_ATTEMPTS:
65+
raise
66+
if e.winerror not in (_winapi.ERROR_PIPE_BUSY,
67+
_winapi.ERROR_ACCESS_DENIED):
68+
raise
6269

6370
h2 = _winapi.CreateFile(
6471
address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,

Lib/ctypes/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ def _load_library(self, name, mode, handle, winmode):
458458
if name and name.endswith(")") and ".a(" in name:
459459
mode |= _os.RTLD_MEMBER | _os.RTLD_NOW
460460
self._name = name
461+
if handle is not None:
462+
return handle
461463
return _dlopen(name, mode)
462464

463465
def __repr__(self):

0 commit comments

Comments
 (0)