Skip to content

Commit 309f392

Browse files
authored
Merge branch 'main' into binaryops_shift
2 parents 3de0283 + 510fefd commit 309f392

87 files changed

Lines changed: 989 additions & 209 deletions

File tree

Some content is hidden

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

.github/workflows/build.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,45 @@ jobs:
527527
config_hash: ${{ needs.check_source.outputs.config_hash }}
528528
free-threading: ${{ matrix.free-threading }}
529529

530+
cross-build-linux:
531+
name: Cross build Linux
532+
runs-on: ubuntu-latest
533+
needs: check_source
534+
if: needs.check_source.outputs.run_tests == 'true'
535+
steps:
536+
- uses: actions/checkout@v4
537+
with:
538+
persist-credentials: false
539+
- name: Runner image version
540+
run: echo "IMAGE_VERSION=${ImageVersion}" >> "$GITHUB_ENV"
541+
- name: Restore config.cache
542+
uses: actions/cache@v4
543+
with:
544+
path: config.cache
545+
key: ${{ github.job }}-${{ runner.os }}-${{ env.IMAGE_VERSION }}-${{ needs.check_source.outputs.config_hash }}
546+
- name: Register gcc problem matcher
547+
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
548+
- name: Set build dir
549+
run:
550+
# an absolute path outside of the working directoy
551+
echo "BUILD_DIR=$(realpath ${{ github.workspace }}/../build)" >> "$GITHUB_ENV"
552+
- name: Install Dependencies
553+
run: sudo ./.github/workflows/posix-deps-apt.sh
554+
- name: Configure host build
555+
run: ./configure --prefix="$BUILD_DIR/host-python"
556+
- name: Install host Python
557+
run: make -j8 install
558+
- name: Run test subset with host build
559+
run: |
560+
"$BUILD_DIR/host-python/bin/python3" -m test test_sysconfig test_site test_embed
561+
- name: Configure cross build
562+
run: ./configure --prefix="$BUILD_DIR/cross-python" --with-build-python="$BUILD_DIR/host-python/bin/python3"
563+
- name: Install cross Python
564+
run: make -j8 install
565+
- name: Run test subset with host build
566+
run: |
567+
"$BUILD_DIR/cross-python/bin/python3" -m test test_sysconfig test_site test_embed
568+
530569
# CIFuzz job based on https://google.github.io/oss-fuzz/getting-started/continuous-integration/
531570
cifuzz:
532571
name: CIFuzz

Doc/c-api/import.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,24 @@ Importing Modules
325325
If Python is initialized multiple times, :c:func:`PyImport_AppendInittab` or
326326
:c:func:`PyImport_ExtendInittab` must be called before each Python
327327
initialization.
328+
329+
330+
.. c:function:: PyObject* PyImport_ImportModuleAttr(PyObject *mod_name, PyObject *attr_name)
331+
332+
Import the module *mod_name* and get its attribute *attr_name*.
333+
334+
Names must be Python :class:`str` objects.
335+
336+
Helper function combining :c:func:`PyImport_Import` and
337+
:c:func:`PyObject_GetAttr`. For example, it can raise :exc:`ImportError` if
338+
the module is not found, and :exc:`AttributeError` if the attribute doesn't
339+
exist.
340+
341+
.. versionadded:: 3.14
342+
343+
.. c:function:: PyObject* PyImport_ImportModuleAttrString(const char *mod_name, const char *attr_name)
344+
345+
Similar to :c:func:`PyImport_ImportModuleAttr`, but names are UTF-8 encoded
346+
strings instead of Python :class:`str` objects.
347+
348+
.. versionadded:: 3.14

Doc/data/refcounts.dat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3052,3 +3052,11 @@ _Py_c_quot:Py_complex:divisor::
30523052
_Py_c_sum:Py_complex:::
30533053
_Py_c_sum:Py_complex:left::
30543054
_Py_c_sum:Py_complex:right::
3055+
3056+
PyImport_ImportModuleAttr:PyObject*::+1:
3057+
PyImport_ImportModuleAttr:PyObject*:mod_name:0:
3058+
PyImport_ImportModuleAttr:PyObject*:attr_name:0:
3059+
3060+
PyImport_ImportModuleAttrString:PyObject*::+1:
3061+
PyImport_ImportModuleAttrString:const char *:mod_name::
3062+
PyImport_ImportModuleAttrString:const char *:attr_name::

Doc/using/configure.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@ General Options
311311

312312
By convention, ``--enable-experimental-jit`` is a shorthand for ``--enable-experimental-jit=yes``.
313313

314+
.. note::
315+
316+
When building CPython with JIT enabled, ensure that your system has Python 3.11 or later installed.
317+
314318
.. versionadded:: 3.13
315319

316320
.. option:: PKG_CONFIG

Doc/whatsnew/3.14.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,11 @@ New features
13221322
* Add :c:func:`PyUnstable_IsImmortal` for determining whether an object is :term:`immortal`,
13231323
for debugging purposes.
13241324

1325+
* Add :c:func:`PyImport_ImportModuleAttr` and
1326+
:c:func:`PyImport_ImportModuleAttrString` helper functions to import a module
1327+
and get an attribute of the module.
1328+
(Contributed by Victor Stinner in :gh:`128911`.)
1329+
13251330

13261331
Limited C API changes
13271332
---------------------

Include/cpython/import.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,10 @@ struct _frozen {
2121
collection of frozen modules: */
2222

2323
PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules;
24+
25+
PyAPI_FUNC(PyObject*) PyImport_ImportModuleAttr(
26+
PyObject *mod_name,
27+
PyObject *attr_name);
28+
PyAPI_FUNC(PyObject*) PyImport_ImportModuleAttrString(
29+
const char *mod_name,
30+
const char *attr_name);

Include/cpython/unicodeobject.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ enum PyUnicode_Kind {
240240
PyUnicode_4BYTE_KIND = 4
241241
};
242242

243+
PyAPI_FUNC(int) PyUnicode_KIND(PyObject *op);
244+
243245
// PyUnicode_KIND(): Return one of the PyUnicode_*_KIND values defined above.
244246
//
245247
// gh-89653: Converting this macro to a static inline function would introduce
@@ -264,13 +266,15 @@ static inline void* _PyUnicode_NONCOMPACT_DATA(PyObject *op) {
264266
return data;
265267
}
266268

267-
static inline void* PyUnicode_DATA(PyObject *op) {
269+
PyAPI_FUNC(void*) PyUnicode_DATA(PyObject *op);
270+
271+
static inline void* _PyUnicode_DATA(PyObject *op) {
268272
if (PyUnicode_IS_COMPACT(op)) {
269273
return _PyUnicode_COMPACT_DATA(op);
270274
}
271275
return _PyUnicode_NONCOMPACT_DATA(op);
272276
}
273-
#define PyUnicode_DATA(op) PyUnicode_DATA(_PyObject_CAST(op))
277+
#define PyUnicode_DATA(op) _PyUnicode_DATA(_PyObject_CAST(op))
274278

275279
/* Return pointers to the canonical representation cast to unsigned char,
276280
Py_UCS2, or Py_UCS4 for direct character access.

Include/internal/pycore_import.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,6 @@ extern int _PyImport_FixupBuiltin(
3131
PyObject *modules
3232
);
3333

34-
// Export for many shared extensions, like '_json'
35-
PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttr(PyObject *, PyObject *);
36-
37-
// Export for many shared extensions, like '_datetime'
38-
PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttrString(const char *, const char *);
39-
4034

4135
struct _import_runtime_state {
4236
/* The builtin modules (defined in config.c). */

Lib/_pyio.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,9 @@ def _read_unlocked(self, n=None):
10621062
if chunk is None:
10631063
return buf[pos:] or None
10641064
else:
1065+
# Avoid slice + copy if there is no data in buf
1066+
if not buf:
1067+
return chunk
10651068
return buf[pos:] + chunk
10661069
chunks = [buf[pos:]] # Strip the consumed bytes.
10671070
current_size = 0
@@ -1674,22 +1677,31 @@ def readall(self):
16741677
except OSError:
16751678
pass
16761679

1677-
result = bytearray()
1680+
result = bytearray(bufsize)
1681+
bytes_read = 0
16781682
while True:
1679-
if len(result) >= bufsize:
1680-
bufsize = len(result)
1681-
bufsize += max(bufsize, DEFAULT_BUFFER_SIZE)
1682-
n = bufsize - len(result)
1683+
if bytes_read >= bufsize:
1684+
# Parallels _io/fileio.c new_buffersize
1685+
if bufsize > 65536:
1686+
addend = bufsize >> 3
1687+
else:
1688+
addend = bufsize + 256
1689+
if addend < DEFAULT_BUFFER_SIZE:
1690+
addend = DEFAULT_BUFFER_SIZE
1691+
bufsize += addend
1692+
result[bytes_read:bufsize] = b'\0'
1693+
assert bufsize - bytes_read > 0, "Should always try and read at least one byte"
16831694
try:
1684-
chunk = os.read(self._fd, n)
1695+
n = os.readinto(self._fd, memoryview(result)[bytes_read:])
16851696
except BlockingIOError:
1686-
if result:
1697+
if bytes_read > 0:
16871698
break
16881699
return None
1689-
if not chunk: # reached the end of the file
1700+
if n == 0: # reached the end of the file
16901701
break
1691-
result += chunk
1702+
bytes_read += n
16921703

1704+
del result[bytes_read:]
16931705
return bytes(result)
16941706

16951707
def readinto(self, buffer):

Lib/_pyrepl/reader.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,10 +587,11 @@ def setpos_from_xy(self, x: int, y: int) -> None:
587587
def pos2xy(self) -> tuple[int, int]:
588588
"""Return the x, y coordinates of position 'pos'."""
589589
# this *is* incomprehensible, yes.
590-
y = 0
590+
p, y = 0, 0
591+
l2: list[int] = []
591592
pos = self.pos
592593
assert 0 <= pos <= len(self.buffer)
593-
if pos == len(self.buffer):
594+
if pos == len(self.buffer) and len(self.screeninfo) > 0:
594595
y = len(self.screeninfo) - 1
595596
p, l2 = self.screeninfo[y]
596597
return p + sum(l2) + l2.count(0), y

0 commit comments

Comments
 (0)