aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_csv.c73
-rw-r--r--Modules/_gdbmmodule.c8
-rw-r--r--Modules/_io/textio.c15
-rw-r--r--Modules/_json.c13
-rw-r--r--Modules/_sqlite/module.c39
-rw-r--r--Modules/_testcapi/unicode.c7
-rw-r--r--Modules/_zstd/_zstdmodule.c3
-rw-r--r--Modules/_zstd/_zstdmodule.h1
-rw-r--r--Modules/_zstd/clinic/compressor.c.h41
-rw-r--r--Modules/_zstd/compressor.c98
-rw-r--r--Modules/clinic/mathmodule.c.h70
-rw-r--r--Modules/hashlib.h9
-rw-r--r--Modules/itertoolsmodule.c27
-rw-r--r--Modules/mathmodule.c40
-rw-r--r--Modules/posixmodule.c24
-rw-r--r--Modules/xxlimited.c11
16 files changed, 413 insertions, 66 deletions
diff --git a/Modules/_csv.c b/Modules/_csv.c
index e5ae853590b..2e04136e0ac 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -237,7 +237,7 @@ _set_int(const char *name, int *target, PyObject *src, int dflt)
int value;
if (!PyLong_CheckExact(src)) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be an integer", name);
+ "\"%s\" must be an integer, not %T", name, src);
return -1;
}
value = PyLong_AsInt(src);
@@ -255,27 +255,29 @@ _set_char_or_none(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt
if (src == NULL) {
*target = dflt;
}
- else {
+ else if (src == Py_None) {
*target = NOT_SET;
- if (src != Py_None) {
- if (!PyUnicode_Check(src)) {
- PyErr_Format(PyExc_TypeError,
- "\"%s\" must be string or None, not %.200s", name,
- Py_TYPE(src)->tp_name);
- return -1;
- }
- Py_ssize_t len = PyUnicode_GetLength(src);
- if (len < 0) {
- return -1;
- }
- if (len != 1) {
- PyErr_Format(PyExc_TypeError,
- "\"%s\" must be a 1-character string",
- name);
- return -1;
- }
- *target = PyUnicode_READ_CHAR(src, 0);
+ }
+ else {
+ // similar to PyArg_Parse("C?")
+ if (!PyUnicode_Check(src)) {
+ PyErr_Format(PyExc_TypeError,
+ "\"%s\" must be a unicode character or None, not %T",
+ name, src);
+ return -1;
+ }
+ Py_ssize_t len = PyUnicode_GetLength(src);
+ if (len < 0) {
+ return -1;
}
+ if (len != 1) {
+ PyErr_Format(PyExc_TypeError,
+ "\"%s\" must be a unicode character or None, "
+ "not a string of length %zd",
+ name, len);
+ return -1;
+ }
+ *target = PyUnicode_READ_CHAR(src, 0);
}
return 0;
}
@@ -287,11 +289,12 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
*target = dflt;
}
else {
+ // similar to PyArg_Parse("C")
if (!PyUnicode_Check(src)) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be string, not %.200s", name,
- Py_TYPE(src)->tp_name);
- return -1;
+ "\"%s\" must be a unicode character, not %T",
+ name, src);
+ return -1;
}
Py_ssize_t len = PyUnicode_GetLength(src);
if (len < 0) {
@@ -299,8 +302,9 @@ _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
}
if (len != 1) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be a 1-character string",
- name);
+ "\"%s\" must be a unicode character, "
+ "not a string of length %zd",
+ name, len);
return -1;
}
*target = PyUnicode_READ_CHAR(src, 0);
@@ -314,16 +318,12 @@ _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt)
if (src == NULL)
*target = PyUnicode_DecodeASCII(dflt, strlen(dflt), NULL);
else {
- if (src == Py_None)
- *target = NULL;
- else if (!PyUnicode_Check(src)) {
+ if (!PyUnicode_Check(src)) {
PyErr_Format(PyExc_TypeError,
- "\"%s\" must be a string", name);
+ "\"%s\" must be a string, not %T", name, src);
return -1;
}
- else {
- Py_XSETREF(*target, Py_NewRef(src));
- }
+ Py_XSETREF(*target, Py_NewRef(src));
}
return 0;
}
@@ -533,11 +533,6 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
/* validate options */
if (dialect_check_quoting(self->quoting))
goto err;
- if (self->delimiter == NOT_SET) {
- PyErr_SetString(PyExc_TypeError,
- "\"delimiter\" must be a 1-character string");
- goto err;
- }
if (quotechar == Py_None && quoting == NULL)
self->quoting = QUOTE_NONE;
if (self->quoting != QUOTE_NONE && self->quotechar == NOT_SET) {
@@ -545,10 +540,6 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
"quotechar must be set if quoting enabled");
goto err;
}
- if (self->lineterminator == NULL) {
- PyErr_SetString(PyExc_TypeError, "lineterminator must be set");
- goto err;
- }
if (dialect_check_char("delimiter", self->delimiter, self, true) ||
dialect_check_char("escapechar", self->escapechar, self,
!self->skipinitialspace) ||
diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c
index 9c402e20e51..6a4939512b2 100644
--- a/Modules/_gdbmmodule.c
+++ b/Modules/_gdbmmodule.c
@@ -814,6 +814,11 @@ dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
iflags |= GDBM_NOLOCK;
break;
#endif
+#ifdef GDBM_NOMMAP
+ case 'm':
+ iflags |= GDBM_NOMMAP;
+ break;
+#endif
default:
PyErr_Format(state->gdbm_error,
"Flag '%c' is not supported.", (unsigned char)*flags);
@@ -847,6 +852,9 @@ static const char gdbmmodule_open_flags[] = "rwcn"
#ifdef GDBM_NOLOCK
"u"
#endif
+#ifdef GDBM_NOMMAP
+ "m"
+#endif
;
static PyMethodDef _gdbm_module_methods[] = {
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 86328e46a7b..3808ecdceb9 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -1578,6 +1578,8 @@ _io_TextIOWrapper_detach_impl(textio *self)
static int
_textiowrapper_writeflush(textio *self)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
+
if (self->pending_bytes == NULL)
return 0;
@@ -3173,8 +3175,9 @@ _io_TextIOWrapper_close_impl(textio *self)
}
static PyObject *
-textiowrapper_iternext(PyObject *op)
+textiowrapper_iternext_lock_held(PyObject *op)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op);
PyObject *line;
textio *self = textio_CAST(op);
@@ -3210,6 +3213,16 @@ textiowrapper_iternext(PyObject *op)
return line;
}
+static PyObject *
+textiowrapper_iternext(PyObject *op)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = textiowrapper_iternext_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return result;
+}
+
/*[clinic input]
@critical_section
@getter
diff --git a/Modules/_json.c b/Modules/_json.c
index 57678ad595f..6b5f6ea42df 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -1603,6 +1603,12 @@ encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *firs
if (*first) {
*first = false;
+ if (s->indent != Py_None) {
+ if (write_newline_indent(writer, indent_level, indent_cache) < 0) {
+ Py_DECREF(keystr);
+ return -1;
+ }
+ }
}
else {
if (PyUnicodeWriter_WriteStr(writer, item_separator) < 0) {
@@ -1670,11 +1676,8 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
if (s->indent != Py_None) {
indent_level++;
separator = get_item_separator(s, indent_level, indent_cache);
- if (separator == NULL ||
- write_newline_indent(writer, indent_level, indent_cache) < 0)
- {
+ if (separator == NULL)
goto bail;
- }
}
if (s->sort_keys || !PyDict_CheckExact(dct)) {
@@ -1714,7 +1717,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
goto bail;
Py_CLEAR(ident);
}
- if (s->indent != Py_None) {
+ if (s->indent != Py_None && !first) {
indent_level--;
if (write_newline_indent(writer, indent_level, indent_cache) < 0) {
goto bail;
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index 909ddd1f990..5464fd1227a 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -32,6 +32,7 @@
#include "microprotocols.h"
#include "row.h"
#include "blob.h"
+#include "util.h"
#if SQLITE_VERSION_NUMBER < 3015002
#error "SQLite 3.15.2 or higher required"
@@ -405,6 +406,40 @@ pysqlite_error_name(int rc)
}
static int
+add_keyword_tuple(PyObject *module)
+{
+#if SQLITE_VERSION_NUMBER >= 3024000
+ int count = sqlite3_keyword_count();
+ PyObject *keywords = PyTuple_New(count);
+ if (keywords == NULL) {
+ return -1;
+ }
+ for (int i = 0; i < count; i++) {
+ const char *keyword;
+ int size;
+ int result = sqlite3_keyword_name(i, &keyword, &size);
+ if (result != SQLITE_OK) {
+ pysqlite_state *state = pysqlite_get_state(module);
+ set_error_from_code(state, result);
+ goto error;
+ }
+ PyObject *kwd = PyUnicode_FromStringAndSize(keyword, size);
+ if (!kwd) {
+ goto error;
+ }
+ PyTuple_SET_ITEM(keywords, i, kwd);
+ }
+ return PyModule_Add(module, "SQLITE_KEYWORDS", keywords);
+
+error:
+ Py_DECREF(keywords);
+ return -1;
+#else
+ return 0;
+#endif
+}
+
+static int
add_integer_constants(PyObject *module) {
#define ADD_INT(ival) \
do { \
@@ -702,6 +737,10 @@ module_exec(PyObject *module)
goto error;
}
+ if (add_keyword_tuple(module) < 0) {
+ goto error;
+ }
+
if (PyModule_AddStringConstant(module, "sqlite_version", sqlite3_libversion())) {
goto error;
}
diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c
index e70f5c68bc3..203282dd53d 100644
--- a/Modules/_testcapi/unicode.c
+++ b/Modules/_testcapi/unicode.c
@@ -220,6 +220,12 @@ unicode_copycharacters(PyObject *self, PyObject *args)
return Py_BuildValue("(Nn)", to_copy, copied);
}
+static PyObject*
+unicode_GET_CACHED_HASH(PyObject *self, PyObject *arg)
+{
+ return PyLong_FromSsize_t(PyUnstable_Unicode_GET_CACHED_HASH(arg));
+}
+
// --- PyUnicodeWriter type -------------------------------------------------
@@ -570,6 +576,7 @@ static PyMethodDef TestMethods[] = {
{"unicode_asucs4copy", unicode_asucs4copy, METH_VARARGS},
{"unicode_asutf8", unicode_asutf8, METH_VARARGS},
{"unicode_copycharacters", unicode_copycharacters, METH_VARARGS},
+ {"unicode_GET_CACHED_HASH", unicode_GET_CACHED_HASH, METH_O},
{NULL},
};
diff --git a/Modules/_zstd/_zstdmodule.c b/Modules/_zstd/_zstdmodule.c
index b0e50f873f4..d75c0779474 100644
--- a/Modules/_zstd/_zstdmodule.c
+++ b/Modules/_zstd/_zstdmodule.c
@@ -72,6 +72,9 @@ set_zstd_error(const _zstd_state *state, error_type type, size_t zstd_ret)
case ERR_COMPRESS:
msg = "Unable to compress Zstandard data: %s";
break;
+ case ERR_SET_PLEDGED_INPUT_SIZE:
+ msg = "Unable to set pledged uncompressed content size: %s";
+ break;
case ERR_LOAD_D_DICT:
msg = "Unable to load Zstandard dictionary or prefix for "
diff --git a/Modules/_zstd/_zstdmodule.h b/Modules/_zstd/_zstdmodule.h
index c73f15b3c52..4e8f708f223 100644
--- a/Modules/_zstd/_zstdmodule.h
+++ b/Modules/_zstd/_zstdmodule.h
@@ -27,6 +27,7 @@ typedef struct {
typedef enum {
ERR_DECOMPRESS,
ERR_COMPRESS,
+ ERR_SET_PLEDGED_INPUT_SIZE,
ERR_LOAD_D_DICT,
ERR_LOAD_C_DICT,
diff --git a/Modules/_zstd/clinic/compressor.c.h b/Modules/_zstd/clinic/compressor.c.h
index f69161b590e..4f8d93fd9e8 100644
--- a/Modules/_zstd/clinic/compressor.c.h
+++ b/Modules/_zstd/clinic/compressor.c.h
@@ -252,4 +252,43 @@ skip_optional_pos:
exit:
return return_value;
}
-/*[clinic end generated code: output=ee2d1dc298de790c input=a9049054013a1b77]*/
+
+PyDoc_STRVAR(_zstd_ZstdCompressor_set_pledged_input_size__doc__,
+"set_pledged_input_size($self, size, /)\n"
+"--\n"
+"\n"
+"Set the uncompressed content size to be written into the frame header.\n"
+"\n"
+" size\n"
+" The size of the uncompressed data to be provided to the compressor.\n"
+"\n"
+"This method can be used to ensure the header of the frame about to be written\n"
+"includes the size of the data, unless the CompressionParameter.content_size_flag\n"
+"is set to False. If last_mode != FLUSH_FRAME, then a RuntimeError is raised.\n"
+"\n"
+"It is important to ensure that the pledged data size matches the actual data\n"
+"size. If they do not match the compressed output data may be corrupted and the\n"
+"final chunk written may be lost.");
+
+#define _ZSTD_ZSTDCOMPRESSOR_SET_PLEDGED_INPUT_SIZE_METHODDEF \
+ {"set_pledged_input_size", (PyCFunction)_zstd_ZstdCompressor_set_pledged_input_size, METH_O, _zstd_ZstdCompressor_set_pledged_input_size__doc__},
+
+static PyObject *
+_zstd_ZstdCompressor_set_pledged_input_size_impl(ZstdCompressor *self,
+ unsigned long long size);
+
+static PyObject *
+_zstd_ZstdCompressor_set_pledged_input_size(PyObject *self, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ unsigned long long size;
+
+ if (!zstd_contentsize_converter(arg, &size)) {
+ goto exit;
+ }
+ return_value = _zstd_ZstdCompressor_set_pledged_input_size_impl((ZstdCompressor *)self, size);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=c1d5c2cf06a8becd input=a9049054013a1b77]*/
diff --git a/Modules/_zstd/compressor.c b/Modules/_zstd/compressor.c
index e1217635f60..bc9e6eff89a 100644
--- a/Modules/_zstd/compressor.c
+++ b/Modules/_zstd/compressor.c
@@ -45,6 +45,52 @@ typedef struct {
#define ZstdCompressor_CAST(op) ((ZstdCompressor *)op)
+/*[python input]
+
+class zstd_contentsize_converter(CConverter):
+ type = 'unsigned long long'
+ converter = 'zstd_contentsize_converter'
+
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=0932c350d633c7de]*/
+
+
+static int
+zstd_contentsize_converter(PyObject *size, unsigned long long *p)
+{
+ // None means the user indicates the size is unknown.
+ if (size == Py_None) {
+ *p = ZSTD_CONTENTSIZE_UNKNOWN;
+ }
+ else {
+ /* ZSTD_CONTENTSIZE_UNKNOWN is 0ULL - 1
+ ZSTD_CONTENTSIZE_ERROR is 0ULL - 2
+ Users should only pass values < ZSTD_CONTENTSIZE_ERROR */
+ unsigned long long pledged_size = PyLong_AsUnsignedLongLong(size);
+ /* Here we check for (unsigned long long)-1 as a sign of an error in
+ PyLong_AsUnsignedLongLong */
+ if (pledged_size == (unsigned long long)-1 && PyErr_Occurred()) {
+ *p = ZSTD_CONTENTSIZE_ERROR;
+ if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+ PyErr_Format(PyExc_ValueError,
+ "size argument should be a positive int less "
+ "than %ull", ZSTD_CONTENTSIZE_ERROR);
+ return 0;
+ }
+ return 0;
+ }
+ if (pledged_size >= ZSTD_CONTENTSIZE_ERROR) {
+ *p = ZSTD_CONTENTSIZE_ERROR;
+ PyErr_Format(PyExc_ValueError,
+ "size argument should be a positive int less "
+ "than %ull", ZSTD_CONTENTSIZE_ERROR);
+ return 0;
+ }
+ *p = pledged_size;
+ }
+ return 1;
+}
+
#include "clinic/compressor.c.h"
static int
@@ -643,9 +689,61 @@ _zstd_ZstdCompressor_flush_impl(ZstdCompressor *self, int mode)
return ret;
}
+
+/*[clinic input]
+_zstd.ZstdCompressor.set_pledged_input_size
+
+ size: zstd_contentsize
+ The size of the uncompressed data to be provided to the compressor.
+ /
+
+Set the uncompressed content size to be written into the frame header.
+
+This method can be used to ensure the header of the frame about to be written
+includes the size of the data, unless the CompressionParameter.content_size_flag
+is set to False. If last_mode != FLUSH_FRAME, then a RuntimeError is raised.
+
+It is important to ensure that the pledged data size matches the actual data
+size. If they do not match the compressed output data may be corrupted and the
+final chunk written may be lost.
+[clinic start generated code]*/
+
+static PyObject *
+_zstd_ZstdCompressor_set_pledged_input_size_impl(ZstdCompressor *self,
+ unsigned long long size)
+/*[clinic end generated code: output=3a09e55cc0e3b4f9 input=afd8a7d78cff2eb5]*/
+{
+ // Error occured while converting argument, should be unreachable
+ assert(size != ZSTD_CONTENTSIZE_ERROR);
+
+ /* Thread-safe code */
+ PyMutex_Lock(&self->lock);
+
+ /* Check the current mode */
+ if (self->last_mode != ZSTD_e_end) {
+ PyErr_SetString(PyExc_ValueError,
+ "set_pledged_input_size() method must be called "
+ "when last_mode == FLUSH_FRAME");
+ PyMutex_Unlock(&self->lock);
+ return NULL;
+ }
+
+ /* Set pledged content size */
+ size_t zstd_ret = ZSTD_CCtx_setPledgedSrcSize(self->cctx, size);
+ PyMutex_Unlock(&self->lock);
+ if (ZSTD_isError(zstd_ret)) {
+ _zstd_state* mod_state = PyType_GetModuleState(Py_TYPE(self));
+ set_zstd_error(mod_state, ERR_SET_PLEDGED_INPUT_SIZE, zstd_ret);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef ZstdCompressor_methods[] = {
_ZSTD_ZSTDCOMPRESSOR_COMPRESS_METHODDEF
_ZSTD_ZSTDCOMPRESSOR_FLUSH_METHODDEF
+ _ZSTD_ZSTDCOMPRESSOR_SET_PLEDGED_INPUT_SIZE_METHODDEF
{NULL, NULL}
};
diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h
index 9df73b187bb..fbb012fb6dd 100644
--- a/Modules/clinic/mathmodule.c.h
+++ b/Modules/clinic/mathmodule.c.h
@@ -628,6 +628,74 @@ exit:
return return_value;
}
+PyDoc_STRVAR(math_isnormal__doc__,
+"isnormal($module, x, /)\n"
+"--\n"
+"\n"
+"Return True if x is normal, and False otherwise.");
+
+#define MATH_ISNORMAL_METHODDEF \
+ {"isnormal", (PyCFunction)math_isnormal, METH_O, math_isnormal__doc__},
+
+static PyObject *
+math_isnormal_impl(PyObject *module, double x);
+
+static PyObject *
+math_isnormal(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ double x;
+
+ if (PyFloat_CheckExact(arg)) {
+ x = PyFloat_AS_DOUBLE(arg);
+ }
+ else
+ {
+ x = PyFloat_AsDouble(arg);
+ if (x == -1.0 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ return_value = math_isnormal_impl(module, x);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(math_issubnormal__doc__,
+"issubnormal($module, x, /)\n"
+"--\n"
+"\n"
+"Return True if x is subnormal, and False otherwise.");
+
+#define MATH_ISSUBNORMAL_METHODDEF \
+ {"issubnormal", (PyCFunction)math_issubnormal, METH_O, math_issubnormal__doc__},
+
+static PyObject *
+math_issubnormal_impl(PyObject *module, double x);
+
+static PyObject *
+math_issubnormal(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ double x;
+
+ if (PyFloat_CheckExact(arg)) {
+ x = PyFloat_AS_DOUBLE(arg);
+ }
+ else
+ {
+ x = PyFloat_AsDouble(arg);
+ if (x == -1.0 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ return_value = math_issubnormal_impl(module, x);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(math_isnan__doc__,
"isnan($module, x, /)\n"
"--\n"
@@ -1110,4 +1178,4 @@ math_ulp(PyObject *module, PyObject *arg)
exit:
return return_value;
}
-/*[clinic end generated code: output=77e7b8c161c39843 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=44bba3a0a052a364 input=a9049054013a1b77]*/
diff --git a/Modules/hashlib.h b/Modules/hashlib.h
index a80b195a765..e82ec92be25 100644
--- a/Modules/hashlib.h
+++ b/Modules/hashlib.h
@@ -86,6 +86,15 @@ _Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string)
}
else if (data == NULL && string != NULL) {
// called as H(string=...)
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "the 'string' keyword parameter is deprecated since "
+ "Python 3.15 and slated for removal in Python 3.19; "
+ "use the 'data' keyword parameter or pass the data "
+ "to hash as a positional argument instead", 1) < 0)
+ {
+ *res = NULL;
+ return -1;
+ }
*res = string;
return 1;
}
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index 943c1e8607b..2003546ce84 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -1124,7 +1124,6 @@ typedef struct {
PyObject *it;
PyObject *saved;
Py_ssize_t index;
- int firstpass;
} cycleobject;
#define cycleobject_CAST(op) ((cycleobject *)(op))
@@ -1165,8 +1164,7 @@ itertools_cycle_impl(PyTypeObject *type, PyObject *iterable)
}
lz->it = it;
lz->saved = saved;
- lz->index = 0;
- lz->firstpass = 0;
+ lz->index = -1;
return (PyObject *)lz;
}
@@ -1199,11 +1197,11 @@ cycle_next(PyObject *op)
cycleobject *lz = cycleobject_CAST(op);
PyObject *item;
- if (lz->it != NULL) {
+ Py_ssize_t index = FT_ATOMIC_LOAD_SSIZE_RELAXED(lz->index);
+
+ if (index < 0) {
item = PyIter_Next(lz->it);
if (item != NULL) {
- if (lz->firstpass)
- return item;
if (PyList_Append(lz->saved, item)) {
Py_DECREF(item);
return NULL;
@@ -1213,15 +1211,22 @@ cycle_next(PyObject *op)
/* Note: StopIteration is already cleared by PyIter_Next() */
if (PyErr_Occurred())
return NULL;
+ index = 0;
+ FT_ATOMIC_STORE_SSIZE_RELAXED(lz->index, 0);
+#ifndef Py_GIL_DISABLED
Py_CLEAR(lz->it);
+#endif
}
if (PyList_GET_SIZE(lz->saved) == 0)
return NULL;
- item = PyList_GET_ITEM(lz->saved, lz->index);
- lz->index++;
- if (lz->index >= PyList_GET_SIZE(lz->saved))
- lz->index = 0;
- return Py_NewRef(item);
+ item = PyList_GetItemRef(lz->saved, index);
+ assert(item);
+ index++;
+ if (index >= PyList_GET_SIZE(lz->saved)) {
+ index = 0;
+ }
+ FT_ATOMIC_STORE_SSIZE_RELAXED(lz->index, index);
+ return item;
}
static PyType_Slot cycle_slots[] = {
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 71d9c1387f5..bbbb4911568 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -3119,6 +3119,44 @@ math_isfinite_impl(PyObject *module, double x)
/*[clinic input]
+math.isnormal
+
+ x: double
+ /
+
+Return True if x is normal, and False otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+math_isnormal_impl(PyObject *module, double x)
+/*[clinic end generated code: output=c7b302b5b89c3541 input=fdaa00c58aa7bc17]*/
+{
+ return PyBool_FromLong(isnormal(x));
+}
+
+
+/*[clinic input]
+math.issubnormal
+
+ x: double
+ /
+
+Return True if x is subnormal, and False otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+math_issubnormal_impl(PyObject *module, double x)
+/*[clinic end generated code: output=4e76ac98ddcae761 input=9a20aba7107d0d95]*/
+{
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+ return PyBool_FromLong(issubnormal(x));
+#else
+ return PyBool_FromLong(isfinite(x) && x && !isnormal(x));
+#endif
+}
+
+
+/*[clinic input]
math.isnan
x: double
@@ -4145,6 +4183,8 @@ static PyMethodDef math_methods[] = {
MATH_HYPOT_METHODDEF
MATH_ISCLOSE_METHODDEF
MATH_ISFINITE_METHODDEF
+ MATH_ISNORMAL_METHODDEF
+ MATH_ISSUBNORMAL_METHODDEF
MATH_ISINF_METHODDEF
MATH_ISNAN_METHODDEF
MATH_ISQRT_METHODDEF
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 588894adeac..7dc5ef39a56 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -8820,14 +8820,14 @@ os_ptsname_impl(PyObject *module, int fd)
#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX)
#ifdef HAVE_PTY_H
#include <pty.h>
-#ifdef HAVE_UTMP_H
-#include <utmp.h>
-#endif /* HAVE_UTMP_H */
#elif defined(HAVE_LIBUTIL_H)
#include <libutil.h>
#elif defined(HAVE_UTIL_H)
#include <util.h>
#endif /* HAVE_PTY_H */
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif /* HAVE_UTMP_H */
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
@@ -9562,6 +9562,24 @@ os_getlogin_impl(PyObject *module)
}
else
result = PyErr_SetFromWindowsErr(GetLastError());
+#elif defined (HAVE_GETLOGIN_R)
+# if defined (HAVE_MAXLOGNAME)
+ char name[MAXLOGNAME + 1];
+# elif defined (HAVE_UT_NAMESIZE)
+ char name[UT_NAMESIZE + 1];
+# else
+ char name[256];
+# endif
+ int err = getlogin_r(name, sizeof(name));
+ if (err) {
+ int old_errno = errno;
+ errno = -err;
+ posix_error();
+ errno = old_errno;
+ }
+ else {
+ result = PyUnicode_DecodeFSDefault(name);
+ }
#else
char *name;
int old_errno = errno;
diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c
index 26ac35734fb..0480fb08498 100644
--- a/Modules/xxlimited.c
+++ b/Modules/xxlimited.c
@@ -424,6 +424,13 @@ xx_clear(PyObject *module)
return 0;
}
+static void
+xx_free(void *module)
+{
+ // allow xx_modexec to omit calling xx_clear on error
+ (void)xx_clear((PyObject *)module);
+}
+
static struct PyModuleDef xxmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "xxlimited",
@@ -433,9 +440,7 @@ static struct PyModuleDef xxmodule = {
.m_slots = xx_slots,
.m_traverse = xx_traverse,
.m_clear = xx_clear,
- /* m_free is not necessary here: xx_clear clears all references,
- * and the module state is deallocated along with the module.
- */
+ .m_free = xx_free,
};