Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Lib/math/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
This module provides access to the mathematical functions
defined by the C standard.
"""

from _math import *

# gh-140824: Fix module name for pickle
def patch_module(objs, module):
Comment on lines +8 to +9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better just to have the module name as math.integer for these functions in C?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In C, function.__module__ is set to the extension name: so set to _math or _math_integer. The whole purpose of this PR is to fix function.__module__.

for obj in objs:
if not hasattr(obj, "__module__"):
continue
obj.__module__ = module
patch_module([obj for name, obj in globals().items()
if not name.startswith('_')], 'math')

from _math_integer import comb, factorial, gcd, isqrt, lcm, perm
patch_module([comb, factorial, gcd, isqrt, lcm, perm], 'math.integer')

del patch_module
5 changes: 5 additions & 0 deletions Lib/math/integer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""
This module provides access to integer related mathematical functions.
"""

from _math_integer import *
21 changes: 21 additions & 0 deletions Lib/test/test_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -2788,6 +2788,27 @@ def assertIsNegativeZero(self, value):
)


class MiscTests(unittest.TestCase):

def test_module_name(self):
# gh-140824: _math and _math_integer extensions are exported as math
# and math.integer names.
math_integer_names = {'comb', 'factorial', 'gcd', 'isqrt', 'lcm', 'perm'}
for name in dir(math):
if name.startswith('_'):
continue
obj = getattr(math, name)
if not hasattr(obj, '__module__'):
continue

if name in math_integer_names:
module = 'math.integer'
else:
module = 'math'
with self.subTest(name=name):
self.assertEqual(obj.__module__, module)


def load_tests(loader, tests, pattern):
from doctest import DocFileSuite
tests.addTest(DocFileSuite(os.path.join("mathdata", "ieee754.txt")))
Expand Down
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,7 @@ LIBSUBDIRS= asyncio \
importlib importlib/resources importlib/metadata \
json \
logging \
math \
multiprocessing multiprocessing/dummy \
pathlib \
profile \
Expand Down
6 changes: 3 additions & 3 deletions Modules/Setup
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ PYTHONPATH=$(COREPYTHONPATH)
#_interpreters _interpretersmodule.c
#_json _json.c
#_lsprof _lsprof.c rotatingtree.c
#_math mathmodule.c
#_math_integer mathintegermodule.c
#_multiprocessing -I$(srcdir)/Modules/_multiprocessing _multiprocessing/multiprocessing.c _multiprocessing/semaphore.c
#_opcode _opcode.c
#_pickle _pickle.c
Expand All @@ -149,17 +151,15 @@ PYTHONPATH=$(COREPYTHONPATH)
#_socket socketmodule.c
#_statistics _statisticsmodule.c
#_struct _struct.c
#_sysconfig _sysconfig.c
#_types _typesmodule.c
#_typing _typingmodule.c
#_zoneinfo _zoneinfo.c
#array arraymodule.c
#binascii binascii.c
#cmath cmathmodule.c
#math mathmodule.c
#_math_integer mathintegermodule.c
#mmap mmapmodule.c
#select selectmodule.c
#_sysconfig _sysconfig.c

# XML
#_elementtree _elementtree.c
Expand Down
2 changes: 1 addition & 1 deletion Modules/Setup.stdlib.in
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
@MODULE__ZONEINFO_TRUE@_zoneinfo _zoneinfo.c

# needs libm
@MODULE_MATH_TRUE@math mathmodule.c
@MODULE_CMATH_TRUE@cmath cmathmodule.c
@MODULE__MATH_TRUE@_math mathmodule.c
@MODULE__STATISTICS_TRUE@_statistics _statisticsmodule.c

# _decimal uses libmpdec
Expand Down
32 changes: 0 additions & 32 deletions Modules/mathintegermodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1236,39 +1236,7 @@ static PyMethodDef math_integer_methods[] = {
{NULL, NULL} /* sentinel */
};

static int
math_integer_exec(PyObject *module)
{
/* Fix the __name__ attribute of the module and the __module__ attribute
* of its functions.
*/
PyObject *name = PyUnicode_FromString("math.integer");
if (name == NULL) {
return -1;
}
if (PyObject_SetAttrString(module, "__name__", name) < 0) {
Py_DECREF(name);
return -1;
}
for (const PyMethodDef *m = math_integer_methods; m->ml_name; m++) {
PyObject *obj = PyObject_GetAttrString(module, m->ml_name);
if (obj == NULL) {
Py_DECREF(name);
return -1;
}
if (PyObject_SetAttrString(obj, "__module__", name) < 0) {
Py_DECREF(name);
Py_DECREF(obj);
return -1;
}
Py_DECREF(obj);
}
Py_DECREF(name);
return 0;
}

static PyModuleDef_Slot math_integer_slots[] = {
{Py_mod_exec, math_integer_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
{0, NULL}
Expand Down
31 changes: 2 additions & 29 deletions Modules/mathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2976,7 +2976,6 @@ math_ulp_impl(PyObject *module, double x)
static int
math_exec(PyObject *module)
{

if (PyModule_Add(module, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) {
return -1;
}
Expand All @@ -2993,32 +2992,6 @@ math_exec(PyObject *module)
if (PyModule_Add(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) {
return -1;
}

PyObject *intmath = PyImport_ImportModule("_math_integer");
if (!intmath) {
return -1;
}
#define IMPORT_FROM_INTMATH(NAME) do { \
if (PyModule_Add(module, #NAME, \
PyObject_GetAttrString(intmath, #NAME)) < 0) { \
Py_DECREF(intmath); \
return -1; \
} \
} while(0)

IMPORT_FROM_INTMATH(comb);
IMPORT_FROM_INTMATH(factorial);
IMPORT_FROM_INTMATH(gcd);
IMPORT_FROM_INTMATH(isqrt);
IMPORT_FROM_INTMATH(lcm);
IMPORT_FROM_INTMATH(perm);
if (_PyImport_SetModuleString("math.integer", intmath) < 0) {
Py_DECREF(intmath);
return -1;
}
if (PyModule_Add(module, "integer", intmath) < 0) {
return -1;
}
return 0;
}

Expand Down Expand Up @@ -3095,15 +3068,15 @@ PyDoc_STRVAR(module_doc,

static struct PyModuleDef mathmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "math",
.m_name = "_math",
.m_doc = module_doc,
.m_size = 0,
.m_methods = math_methods,
.m_slots = math_slots,
};

PyMODINIT_FUNC
PyInit_math(void)
PyInit__math(void)
{
return PyModuleDef_Init(&mathmodule);
}
4 changes: 2 additions & 2 deletions PC/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ extern PyObject* PyInit_faulthandler(void);
extern PyObject* PyInit__tracemalloc(void);
extern PyObject* PyInit_gc(void);
extern PyObject* PyInit__math_integer(void);
extern PyObject* PyInit_math(void);
extern PyObject* PyInit__math(void);
extern PyObject* PyInit_nt(void);
extern PyObject* PyInit__operator(void);
extern PyObject* PyInit__signal(void);
Expand Down Expand Up @@ -102,7 +102,7 @@ struct _inittab _PyImport_Inittab[] = {
{"faulthandler", PyInit_faulthandler},
{"gc", PyInit_gc},
{"_math_integer", PyInit__math_integer},
{"math", PyInit_math},
{"_math", PyInit__math},
{"nt", PyInit_nt}, /* Use the NT os functions, not posix */
{"_operator", PyInit__operator},
{"_signal", PyInit__signal},
Expand Down
1 change: 1 addition & 0 deletions Python/stdlib_module_names.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 28 additions & 28 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -7911,9 +7911,9 @@ PY_STDLIB_MOD([_posixshmem],
[$POSIXSHMEM_CFLAGS], [$POSIXSHMEM_LIBS])

dnl needs libm
PY_STDLIB_MOD_SIMPLE([_math], [], [$LIBM])
PY_STDLIB_MOD_SIMPLE([_statistics], [], [$LIBM])
PY_STDLIB_MOD_SIMPLE([cmath], [], [$LIBM])
PY_STDLIB_MOD_SIMPLE([math], [], [$LIBM])

dnl needs libm and on some platforms librt
PY_STDLIB_MOD_SIMPLE([_datetime], [], [$TIMEMODULE_LIB $LIBM])
Expand Down
Loading