Skip to content

Commit

Permalink
Merge branch 'main' into docs/gh112346
Browse files Browse the repository at this point in the history
  • Loading branch information
gpshead committed Jun 15, 2024
2 parents 3b63de2 + 08d09cf commit acf01da
Show file tree
Hide file tree
Showing 50 changed files with 1,094 additions and 200 deletions.
10 changes: 7 additions & 3 deletions Doc/library/ast.rst
Original file line number Diff line number Diff line change
Expand Up @@ -891,9 +891,13 @@ Statements
An assignment with a type annotation. ``target`` is a single node and can
be a :class:`Name`, a :class:`Attribute` or a :class:`Subscript`.
``annotation`` is the annotation, such as a :class:`Constant` or :class:`Name`
node. ``value`` is a single optional node. ``simple`` is a boolean integer
set to True for a :class:`Name` node in ``target`` that do not appear in
between parenthesis and are hence pure names and not expressions.
node. ``value`` is a single optional node.

``simple`` is always either 0 (indicating a "complex" target) or 1
(indicating a "simple" target). A "simple" target consists solely of a
:class:`Name` node that does not appear between parentheses; all other
targets are considered complex. Only simple targets appear in
the :attr:`__annotations__` dictionary of modules and classes.

.. doctest::

Expand Down
2 changes: 1 addition & 1 deletion Doc/library/enum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ Data Types

``Flag`` is the same as :class:`Enum`, but its members support the bitwise
operators ``&`` (*AND*), ``|`` (*OR*), ``^`` (*XOR*), and ``~`` (*INVERT*);
the results of those operators are members of the enumeration.
the results of those operations are (aliases of) members of the enumeration.

.. method:: __contains__(self, value)

Expand Down
8 changes: 5 additions & 3 deletions Doc/library/gzip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,7 @@ The module defines the following items:

Compress the *data*, returning a :class:`bytes` object containing
the compressed data. *compresslevel* and *mtime* have the same meaning as in
the :class:`GzipFile` constructor above. When *mtime* is set to ``0``, this
function is equivalent to :func:`zlib.compress` with *wbits* set to ``31``.
The zlib function is faster.
the :class:`GzipFile` constructor above.

.. versionadded:: 3.2
.. versionchanged:: 3.8
Expand All @@ -202,6 +200,10 @@ The module defines the following items:
output may contain a gzip header "OS" byte value other than 255
"unknown" as supplied by the underlying zlib implementation.

.. versionchanged:: 3.13
The gzip header OS byte is guaranteed to be set to 255 when this function
is used as was the case in 3.10 and earlier.

.. function:: decompress(data)

Decompress the *data*, returning a :class:`bytes` object containing the
Expand Down
18 changes: 16 additions & 2 deletions Doc/library/pathlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1429,8 +1429,22 @@ Creating files and directories
available. In previous versions, :exc:`NotImplementedError` was raised.


Renaming and deleting
^^^^^^^^^^^^^^^^^^^^^
Copying, renaming and deleting
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. method:: Path.copy(target)

Copy the contents of this file to the *target* file. If *target* specifies
a file that already exists, it will be replaced.

.. note::
This method uses operating system functionality to copy file content
efficiently. The OS might also copy some metadata, such as file
permissions. After the copy is complete, users may wish to call
:meth:`Path.chmod` to set the permissions of the target file.

.. versionadded:: 3.14


.. method:: Path.rename(target)

Expand Down
10 changes: 8 additions & 2 deletions Doc/library/pdb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,17 @@ can be overridden by the local file.
argument must be an identifier, ``help exec`` must be entered to get help on
the ``!`` command.

.. pdbcommand:: w(here)
.. pdbcommand:: w(here) [count]

Print a stack trace, with the most recent frame at the bottom. An arrow (``>``)
Print a stack trace, with the most recent frame at the bottom. if *count*
is 0, print the current frame entry. If *count* is negative, print the least
recent - *count* frames. If *count* is positive, print the most recent
*count* frames. An arrow (``>``)
indicates the current frame, which determines the context of most commands.

.. versionchanged:: 3.14
*count* argument is added.

.. pdbcommand:: d(own) [count]

Move the current frame *count* (default one) levels down in the stack trace
Expand Down
7 changes: 5 additions & 2 deletions Doc/reference/simple_stmts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -333,15 +333,18 @@ statement, of a variable or attribute annotation and an optional assignment stat

The difference from normal :ref:`assignment` is that only a single target is allowed.

For simple names as assignment targets, if in class or module scope,
The assignment target is considered "simple" if it consists of a single
name that is not enclosed in parentheses.
For simple assignment targets, if in class or module scope,
the annotations are evaluated and stored in a special class or module
attribute :attr:`__annotations__`
that is a dictionary mapping from variable names (mangled if private) to
evaluated annotations. This attribute is writable and is automatically
created at the start of class or module body execution, if annotations
are found statically.

For expressions as assignment targets, the annotations are evaluated if
If the assignment target is not simple (an attribute, subscript node, or
parenthesized name), the annotation is evaluated if
in class or module scope, but not stored.

If a name is annotated in a function scope, then this name is local for
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ os
by :func:`os.unsetenv`, or made outside Python in the same process.
(Contributed by Victor Stinner in :gh:`120057`.)

pathlib
-------

* Add :meth:`pathlib.Path.copy`, which copies the content of one file to
another, like :func:`shutil.copyfile`.
(Contributed by Barney Gale in :gh:`73991`.)

symtable
--------

Expand Down
24 changes: 15 additions & 9 deletions Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,25 @@ extern "C" {
#define _Py_TYPE_BASE_VERSION_TAG (2<<16)
#define _Py_MAX_GLOBAL_TYPE_VERSION_TAG (_Py_TYPE_BASE_VERSION_TAG - 1)

/* For now we hard-code this to a value for which we are confident
all the static builtin types will fit (for all builds). */
#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES 200
#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10
#define _Py_MAX_MANAGED_STATIC_TYPES \
(_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES + _Py_MAX_MANAGED_STATIC_EXT_TYPES)

struct _types_runtime_state {
/* Used to set PyTypeObject.tp_version_tag for core static types. */
// bpo-42745: next_version_tag remains shared by all interpreters
// because of static types.
unsigned int next_version_tag;

struct {
struct {
PyTypeObject *type;
int64_t interp_count;
} types[_Py_MAX_MANAGED_STATIC_TYPES];
} managed_static;
};


Expand All @@ -42,11 +56,6 @@ struct type_cache {
struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP];
};

/* For now we hard-code this to a value for which we are confident
all the static builtin types will fit (for all builds). */
#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES 200
#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10

typedef struct {
PyTypeObject *type;
int isbuiltin;
Expand Down Expand Up @@ -133,6 +142,7 @@ struct types_state {

extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
extern void _PyTypes_FiniTypes(PyInterpreterState *);
extern void _PyTypes_FiniExtTypes(PyInterpreterState *interp);
extern void _PyTypes_Fini(PyInterpreterState *);
extern void _PyTypes_AfterFork(void);

Expand Down Expand Up @@ -171,10 +181,6 @@ extern managed_static_type_state * _PyStaticType_GetState(
PyAPI_FUNC(int) _PyStaticType_InitForExtension(
PyInterpreterState *interp,
PyTypeObject *self);
PyAPI_FUNC(void) _PyStaticType_FiniForExtension(
PyInterpreterState *interp,
PyTypeObject *self,
int final);


/* Like PyType_GetModuleState, but skips verification
Expand Down
6 changes: 5 additions & 1 deletion Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,11 @@ PyType_HasFeature(PyTypeObject *type, unsigned long feature)
// PyTypeObject is opaque in the limited C API
flags = PyType_GetFlags(type);
#else
flags = type->tp_flags;
# ifdef Py_GIL_DISABLED
flags = _Py_atomic_load_ulong_relaxed(&type->tp_flags);
# else
flags = type->tp_flags;
# endif
#endif
return ((flags & feature) != 0);
}
Expand Down
4 changes: 2 additions & 2 deletions Lib/collections/abc.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from _collections_abc import *
from _collections_abc import __all__
from _collections_abc import _CallableGenericAlias
from _collections_abc import __all__ # noqa: F401
from _collections_abc import _CallableGenericAlias # noqa: F401
38 changes: 8 additions & 30 deletions Lib/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,43 +580,21 @@ def _rewind(self):
self._new_member = True


def _create_simple_gzip_header(compresslevel: int,
mtime = None) -> bytes:
"""
Write a simple gzip header with no extra fields.
:param compresslevel: Compresslevel used to determine the xfl bytes.
:param mtime: The mtime (must support conversion to a 32-bit integer).
:return: A bytes object representing the gzip header.
"""
if mtime is None:
mtime = time.time()
if compresslevel == _COMPRESS_LEVEL_BEST:
xfl = 2
elif compresslevel == _COMPRESS_LEVEL_FAST:
xfl = 4
else:
xfl = 0
# Pack ID1 and ID2 magic bytes, method (8=deflate), header flags (no extra
# fields added to header), mtime, xfl and os (255 for unknown OS).
return struct.pack("<BBBBLBB", 0x1f, 0x8b, 8, 0, int(mtime), xfl, 255)


def compress(data, compresslevel=_COMPRESS_LEVEL_BEST, *, mtime=None):
"""Compress data in one shot and return the compressed string.
compresslevel sets the compression level in range of 0-9.
mtime can be used to set the modification time. The modification time is
set to the current time by default.
"""
if mtime == 0:
# Use zlib as it creates the header with 0 mtime by default.
# This is faster and with less overhead.
return zlib.compress(data, level=compresslevel, wbits=31)
header = _create_simple_gzip_header(compresslevel, mtime)
trailer = struct.pack("<LL", zlib.crc32(data), (len(data) & 0xffffffff))
# Wbits=-15 creates a raw deflate block.
return (header + zlib.compress(data, level=compresslevel, wbits=-15) +
trailer)
# Wbits=31 automatically includes a gzip header and trailer.
gzip_data = zlib.compress(data, level=compresslevel, wbits=31)
if mtime is None:
mtime = time.time()
# Reuse gzip header created by zlib, replace mtime and OS byte for
# consistency.
header = struct.pack("<4sLBB", gzip_data, int(mtime), gzip_data[8], 255)
return header + gzip_data[10:]


def decompress(data):
Expand Down
8 changes: 8 additions & 0 deletions Lib/importlib/machinery.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,11 @@
def all_suffixes():
"""Returns a list of all recognized module suffixes for this process"""
return SOURCE_SUFFIXES + BYTECODE_SUFFIXES + EXTENSION_SUFFIXES


__all__ = ['AppleFrameworkLoader', 'BYTECODE_SUFFIXES', 'BuiltinImporter',
'DEBUG_BYTECODE_SUFFIXES', 'EXTENSION_SUFFIXES',
'ExtensionFileLoader', 'FileFinder', 'FrozenImporter', 'ModuleSpec',
'NamespaceLoader', 'OPTIMIZED_BYTECODE_SUFFIXES', 'PathFinder',
'SOURCE_SUFFIXES', 'SourceFileLoader', 'SourcelessFileLoader',
'WindowsRegistryFinder', 'all_suffixes']
6 changes: 6 additions & 0 deletions Lib/importlib/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,9 @@ def exec_module(self, module):
loader_state['is_loading'] = False
module.__spec__.loader_state = loader_state
module.__class__ = _LazyModule


__all__ = ['LazyLoader', 'Loader', 'MAGIC_NUMBER',
'cache_from_source', 'decode_source', 'find_spec',
'module_from_spec', 'resolve_name', 'source_from_cache',
'source_hash', 'spec_from_file_location', 'spec_from_loader']
30 changes: 30 additions & 0 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import posixpath
from glob import _GlobberBase, _no_recurse_symlinks
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
from ._os import copyfileobj


__all__ = ["UnsupportedOperation"]
Expand Down Expand Up @@ -563,6 +564,15 @@ def samefile(self, other_path):
return (st.st_ino == other_st.st_ino and
st.st_dev == other_st.st_dev)

def _samefile_safe(self, other_path):
"""
Like samefile(), but returns False rather than raising OSError.
"""
try:
return self.samefile(other_path)
except (OSError, ValueError):
return False

def open(self, mode='r', buffering=-1, encoding=None,
errors=None, newline=None):
"""
Expand Down Expand Up @@ -780,6 +790,26 @@ def mkdir(self, mode=0o777, parents=False, exist_ok=False):
"""
raise UnsupportedOperation(self._unsupported_msg('mkdir()'))

def copy(self, target):
"""
Copy the contents of this file to the given target.
"""
if not isinstance(target, PathBase):
target = self.with_segments(target)
if self._samefile_safe(target):
raise OSError(f"{self!r} and {target!r} are the same file")
with self.open('rb') as source_f:
try:
with target.open('wb') as target_f:
copyfileobj(source_f, target_f)
except IsADirectoryError as e:
if not target.exists():
# Raise a less confusing exception.
raise FileNotFoundError(
f'Directory does not exist: {target}') from e
else:
raise

def rename(self, target):
"""
Rename this path to the target path.
Expand Down
16 changes: 16 additions & 0 deletions Lib/pathlib/_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
grp = None

from ._abc import UnsupportedOperation, PurePathBase, PathBase
from ._os import copyfile


__all__ = [
Expand Down Expand Up @@ -780,6 +781,21 @@ def mkdir(self, mode=0o777, parents=False, exist_ok=False):
if not exist_ok or not self.is_dir():
raise

if copyfile:
def copy(self, target):
"""
Copy the contents of this file to the given target.
"""
try:
target = os.fspath(target)
except TypeError:
if isinstance(target, PathBase):
# Target is an instance of PathBase but not os.PathLike.
# Use generic implementation from PathBase.
return PathBase.copy(self, target)
raise
copyfile(os.fspath(self), target)

def chmod(self, mode, *, follow_symlinks=True):
"""
Change the permissions of the path, like os.chmod().
Expand Down
Loading

0 comments on commit acf01da

Please sign in to comment.