Skip to content

Commit

Permalink
Merge branch 'main' into pseudo-jumps
Browse files Browse the repository at this point in the history
  • Loading branch information
iritkatriel authored Sep 25, 2024
2 parents 02d0626 + 8447c93 commit 468ce65
Show file tree
Hide file tree
Showing 38 changed files with 404 additions and 186 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,14 @@ jobs:

build_ubuntu_ssltests:
name: 'Ubuntu SSL tests with OpenSSL'
runs-on: ubuntu-22.04
runs-on: ${{ matrix.os }}
timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04]
openssl_ver: [3.0.15, 3.1.7, 3.2.3, 3.3.2]
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
Expand Down Expand Up @@ -231,7 +232,7 @@ jobs:
uses: actions/cache@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
Expand Down Expand Up @@ -410,7 +411,7 @@ jobs:
uses: actions/cache@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/jit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ jobs:
CC="${{ matrix.compiler == 'clang' && 'clang --target=$HOST' || '$HOST-gcc' }}" \
CPP="$CC --preprocess" \
HOSTRUNNER=qemu-${{ matrix.architecture }} \
./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--enable-optimizations --with-lto' }} --build=x86_64-linux-gnu --host="$HOST" --with-build-python=../build/bin/python3 --with-pkg-config=no ac_cv_buggy_getaddrinfo=no ac_cv_file__dev_ptc=no ac_cv_file__dev_ptmx=yes
./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '--with-lto' }} --build=x86_64-linux-gnu --host="$HOST" --with-build-python=../build/bin/python3 --with-pkg-config=no ac_cv_buggy_getaddrinfo=no ac_cv_file__dev_ptc=no ac_cv_file__dev_ptmx=yes
make all --jobs 4
./python -m test --ignorefile=Tools/jit/ignore-tests-emulated-linux.txt --multiprocess 0 --timeout 4500 --verbose2 --verbose3
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/reusable-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ jobs:
build_ubuntu_reusable:
name: 'build and test'
timeout-minutes: 60
runs-on: ubuntu-22.04
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04]
env:
FORCE_COLOR: 1
OPENSSL_VER: 3.0.15
Expand All @@ -36,7 +40,7 @@ jobs:
uses: actions/cache@v4
with:
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
key: ${{ matrix.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
- name: Install OpenSSL
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
Expand Down
24 changes: 20 additions & 4 deletions Doc/library/calendar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -393,13 +393,22 @@ The :mod:`calendar` module exports the following data attributes:

.. data:: day_name

An array that represents the days of the week in the current locale.
A sequence that represents the days of the week in the current locale,
where Monday is day number 0.

>>> import calendar
>>> list(calendar.day_name)
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']


.. data:: day_abbr

An array that represents the abbreviated days of the week in the current locale.
A sequence that represents the abbreviated days of the week in the current locale,
where Mon is day number 0.

>>> import calendar
>>> list(calendar.day_abbr)
['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']

.. data:: MONDAY
TUESDAY
Expand All @@ -426,17 +435,24 @@ The :mod:`calendar` module exports the following data attributes:

.. data:: month_name

An array that represents the months of the year in the current locale. This
A sequence that represents the months of the year in the current locale. This
follows normal convention of January being month number 1, so it has a length of
13 and ``month_name[0]`` is the empty string.

>>> import calendar
>>> list(calendar.month_name)
['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']


.. data:: month_abbr

An array that represents the abbreviated months of the year in the current
A sequence that represents the abbreviated months of the year in the current
locale. This follows normal convention of January being month number 1, so it
has a length of 13 and ``month_abbr[0]`` is the empty string.

>>> import calendar
>>> list(calendar.month_abbr)
['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

.. data:: JANUARY
FEBRUARY
Expand Down
7 changes: 0 additions & 7 deletions Doc/library/dataclasses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,6 @@ Module contents
If :attr:`!__slots__` is already defined in the class, then :exc:`TypeError`
is raised.

.. warning::
Calling no-arg :func:`super` in dataclasses using ``slots=True``
will result in the following exception being raised:
``TypeError: super(type, obj): obj must be an instance or subtype of type``.
The two-arg :func:`super` is a valid workaround.
See :gh:`90562` for full details.

.. warning::
Passing parameters to a base class :meth:`~object.__init_subclass__`
when using ``slots=True`` will result in a :exc:`TypeError`.
Expand Down
8 changes: 7 additions & 1 deletion Doc/library/pdb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,15 @@ slightly different way:
is entered.


.. function:: set_trace(*, header=None)
.. function:: set_trace(*, header=None, commands=None)

Enter the debugger at the calling stack frame. This is useful to hard-code
a breakpoint at a given point in a program, even if the code is not
otherwise being debugged (e.g. when an assertion fails). If given,
*header* is printed to the console just before debugging begins.
The *commands* argument, if given, is a list of commands to execute
when the debugger starts.


.. versionchanged:: 3.7
The keyword-only argument *header*.
Expand All @@ -173,6 +176,9 @@ slightly different way:
:func:`set_trace` will enter the debugger immediately, rather than
on the next line of code to be executed.

.. versionadded:: 3.14
The *commands* argument.

.. function:: post_mortem(traceback=None)

Enter post-mortem debugging of the given *traceback* object. If no
Expand Down
13 changes: 7 additions & 6 deletions Doc/library/shutil.rst
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,10 @@ Directory and files operations
*mode* is a permission mask passed to :func:`os.access`, by default
determining if the file exists and is executable.

*path* is a "``PATH`` string" specifying the lookup directory list. When no
*path* is specified, the results of :func:`os.environ` are used, returning
either the "PATH" value or a fallback of :data:`os.defpath`.
*path* is a "``PATH`` string" specifying the directories to look in,
delimited by :data:`os.pathsep`. When no *path* is specified, the
:envvar:`PATH` environment variable is read from :data:`os.environ`,
falling back to :data:`os.defpath` if it is not set.

On Windows, the current directory is prepended to the *path* if *mode* does
not include ``os.X_OK``. When the *mode* does include ``os.X_OK``, the
Expand All @@ -460,9 +461,9 @@ Directory and files operations
consulting the current working directory for executables: set the environment
variable ``NoDefaultCurrentDirectoryInExePath``.

Also on Windows, the ``PATHEXT`` variable is used to resolve commands
that may not already include an extension. For example, if you call
``shutil.which("python")``, :func:`which` will search ``PATHEXT``
Also on Windows, the :envvar:`PATHEXT` environment variable is used to
resolve commands that may not already include an extension. For example,
if you call ``shutil.which("python")``, :func:`which` will search ``PATHEXT``
to know that it should look for ``python.exe`` within the *path*
directories. For example, on Windows::

Expand Down
26 changes: 17 additions & 9 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ enum _frameowner {
typedef struct _PyInterpreterFrame {
_PyStackRef f_executable; /* Deferred or strong reference (code object or None) */
struct _PyInterpreterFrame *previous;
PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */
_PyStackRef f_funcobj; /* Deferred or strong reference. Only valid if not on C stack */
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
Expand All @@ -84,6 +84,12 @@ static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) {
return (PyCodeObject *)executable;
}

static inline PyFunctionObject *_PyFrame_GetFunction(_PyInterpreterFrame *f) {
PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj);
assert(PyFunction_Check(func));
return (PyFunctionObject *)func;
}

static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) {
return (f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus);
}
Expand Down Expand Up @@ -144,14 +150,15 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *
*/
static inline void
_PyFrame_Initialize(
_PyInterpreterFrame *frame, PyFunctionObject *func,
_PyInterpreterFrame *frame, _PyStackRef func,
PyObject *locals, PyCodeObject *code, int null_locals_from, _PyInterpreterFrame *previous)
{
frame->previous = previous;
frame->f_funcobj = (PyObject *)func;
frame->f_funcobj = func;
frame->f_executable = PyStackRef_FromPyObjectNew(code);
frame->f_builtins = func->func_builtins;
frame->f_globals = func->func_globals;
PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func);
frame->f_builtins = func_obj->func_builtins;
frame->f_globals = func_obj->func_globals;
frame->f_locals = locals;
frame->stackpointer = frame->localsplus + code->co_nlocalsplus;
frame->frame_obj = NULL;
Expand Down Expand Up @@ -300,10 +307,11 @@ PyAPI_FUNC(void) _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFr
* Must be guarded by _PyThreadState_HasStackSpace()
* Consumes reference to func. */
static inline _PyInterpreterFrame *
_PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_locals_from, _PyInterpreterFrame * previous)
_PyFrame_PushUnchecked(PyThreadState *tstate, _PyStackRef func, int null_locals_from, _PyInterpreterFrame * previous)
{
CALL_STAT_INC(frames_pushed);
PyCodeObject *code = (PyCodeObject *)func->func_code;
PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func);
PyCodeObject *code = (PyCodeObject *)func_obj->func_code;
_PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top;
tstate->datastack_top += code->co_framesize;
assert(tstate->datastack_top < tstate->datastack_limit);
Expand All @@ -321,7 +329,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
tstate->datastack_top += code->co_framesize;
assert(tstate->datastack_top < tstate->datastack_limit);
frame->previous = previous;
frame->f_funcobj = Py_None;
frame->f_funcobj = PyStackRef_None;
frame->f_executable = PyStackRef_FromPyObjectNew(code);
#ifdef Py_DEBUG
frame->f_builtins = NULL;
Expand All @@ -345,7 +353,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
}

PyAPI_FUNC(_PyInterpreterFrame *)
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
_PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func,
PyObject *locals, _PyStackRef const* args,
size_t argcount, PyObject *kwnames,
_PyInterpreterFrame *previous);
Expand Down
11 changes: 11 additions & 0 deletions Include/internal/pycore_gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,17 @@ union _PyStackRef;
extern int _PyGC_VisitFrameStack(struct _PyInterpreterFrame *frame, visitproc visit, void *arg);
extern int _PyGC_VisitStackRef(union _PyStackRef *ref, visitproc visit, void *arg);

// Like Py_VISIT but for _PyStackRef fields
#define _Py_VISIT_STACKREF(ref) \
do { \
if (!PyStackRef_IsNull(ref)) { \
int vret = _PyGC_VisitStackRef(&(ref), visit, arg); \
if (vret) \
return vret; \
} \
} while (0)


#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 2 additions & 2 deletions Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1804,8 +1804,8 @@ def add_subparsers(self, **kwargs):
kwargs.setdefault('parser_class', type(self))

if 'title' in kwargs or 'description' in kwargs:
title = _(kwargs.pop('title', 'subcommands'))
description = _(kwargs.pop('description', None))
title = kwargs.pop('title', _('subcommands'))
description = kwargs.pop('description', None)
self._subparsers = self.add_argument_group(title, description)
else:
self._subparsers = self._positionals
Expand Down
62 changes: 50 additions & 12 deletions Lib/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -690,11 +690,8 @@ def _frozen_get_del_attr(cls, fields, func_builder):


def _is_classvar(a_type, typing):
# This test uses a typing internal class, but it's the best way to
# test if this is a ClassVar.
return (a_type is typing.ClassVar
or (type(a_type) is typing._GenericAlias
and a_type.__origin__ is typing.ClassVar))
or (typing.get_origin(a_type) is typing.ClassVar))


def _is_initvar(a_type, dataclasses):
Expand Down Expand Up @@ -1221,9 +1218,31 @@ def _get_slots(cls):
raise TypeError(f"Slots of '{cls.__name__}' cannot be determined")


def _update_func_cell_for__class__(f, oldcls, newcls):
# Returns True if we update a cell, else False.
if f is None:
# f will be None in the case of a property where not all of
# fget, fset, and fdel are used. Nothing to do in that case.
return False
try:
idx = f.__code__.co_freevars.index("__class__")
except ValueError:
# This function doesn't reference __class__, so nothing to do.
return False
# Fix the cell to point to the new class, if it's already pointing
# at the old class. I'm not convinced that the "is oldcls" test
# is needed, but other than performance can't hurt.
closure = f.__closure__[idx]
if closure.cell_contents is oldcls:
closure.cell_contents = newcls
return True
return False


def _add_slots(cls, is_frozen, weakref_slot):
# Need to create a new class, since we can't set __slots__
# after a class has been created.
# Need to create a new class, since we can't set __slots__ after a
# class has been created, and the @dataclass decorator is called
# after the class is created.

# Make sure __slots__ isn't already set.
if '__slots__' in cls.__dict__:
Expand Down Expand Up @@ -1262,18 +1281,37 @@ def _add_slots(cls, is_frozen, weakref_slot):

# And finally create the class.
qualname = getattr(cls, '__qualname__', None)
cls = type(cls)(cls.__name__, cls.__bases__, cls_dict)
newcls = type(cls)(cls.__name__, cls.__bases__, cls_dict)
if qualname is not None:
cls.__qualname__ = qualname
newcls.__qualname__ = qualname

if is_frozen:
# Need this for pickling frozen classes with slots.
if '__getstate__' not in cls_dict:
cls.__getstate__ = _dataclass_getstate
newcls.__getstate__ = _dataclass_getstate
if '__setstate__' not in cls_dict:
cls.__setstate__ = _dataclass_setstate

return cls
newcls.__setstate__ = _dataclass_setstate

# Fix up any closures which reference __class__. This is used to
# fix zero argument super so that it points to the correct class
# (the newly created one, which we're returning) and not the
# original class. We can break out of this loop as soon as we
# make an update, since all closures for a class will share a
# given cell.
for member in newcls.__dict__.values():
# If this is a wrapped function, unwrap it.
member = inspect.unwrap(member)

if isinstance(member, types.FunctionType):
if _update_func_cell_for__class__(member, cls, newcls):
break
elif isinstance(member, property):
if (_update_func_cell_for__class__(member.fget, cls, newcls)
or _update_func_cell_for__class__(member.fset, cls, newcls)
or _update_func_cell_for__class__(member.fdel, cls, newcls)):
break

return newcls


def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False,
Expand Down
4 changes: 2 additions & 2 deletions Lib/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,11 +389,11 @@ def __init__(self, out):
# still use input() to get user input
self.use_rawinput = 1

def set_trace(self, frame=None):
def set_trace(self, frame=None, *, commands=None):
self.__debugger_used = True
if frame is None:
frame = sys._getframe().f_back
pdb.Pdb.set_trace(self, frame)
pdb.Pdb.set_trace(self, frame, commands=commands)

def set_continue(self):
# Calling set_continue unconditionally would break unit test
Expand Down
Loading

0 comments on commit 468ce65

Please sign in to comment.