diff options
author | Antoine Pitrou <antoine@python.org> | 2021-03-21 16:27:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-21 16:27:54 (GMT) |
commit | cdddc2b742750e3f289305cf276433a8170c32c1 (patch) | |
tree | e4ce948d8cff600cf5721ba00c627f780217a64d /Modules | |
parent | 77cde5042a2f1eae489c11a67540afaf43cd5cdf (diff) | |
download | cpython-cdddc2b742750e3f289305cf276433a8170c32c1.zip cpython-cdddc2b742750e3f289305cf276433a8170c32c1.tar.gz cpython-cdddc2b742750e3f289305cf276433a8170c32c1.tar.bz2 |
bpo-43422: Revert _decimal C API addition (GH-24960)
Stefan Krah requested the reversal of these (unreleased) changes, quoting him:
> The capsule API does not meet my testing standards, since I've focused
on the upstream mpdecimal in the last couple of months.
> Additionally, I'd like to refine the API, perhaps together with the
Arrow community.
Automerge-Triggered-By: GH:pitrou
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_decimal/_decimal.c | 200 | ||||
-rw-r--r-- | Modules/_decimal/tests/bench.py | 9 | ||||
-rw-r--r-- | Modules/_decimal/tests/deccheck.py | 81 | ||||
-rw-r--r-- | Modules/_decimal/tests/formathelper.py | 5 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 253 |
5 files changed, 19 insertions, 529 deletions
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 664d45a..83e237d 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2020 Stefan Krah. All rights reserved. + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,8 +33,6 @@ #include <stdlib.h> -#define CPYTHON_DECIMAL_MODULE -#include "pydecimal.h" #include "docstrings.h" @@ -5570,175 +5568,6 @@ static PyTypeObject PyDecContext_Type = }; -/****************************************************************************/ -/* C-API */ -/****************************************************************************/ - -/* Simple API */ -static int -PyDec_TypeCheck(const PyObject *v) -{ - return PyDec_Check(v); -} - -static int -PyDec_IsSpecial(const PyObject *v) -{ - if (!PyDec_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "PyDec_IsSpecial: argument must be a Decimal"); - return -1; - } - - return mpd_isspecial(MPD(v)); -} - -static int -PyDec_IsNaN(const PyObject *v) -{ - if (!PyDec_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "PyDec_IsNaN: argument must be a Decimal"); - return -1; - } - - return mpd_isnan(MPD(v)); -} - -static int -PyDec_IsInfinite(const PyObject *v) -{ - if (!PyDec_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "PyDec_IsInfinite: argument must be a Decimal"); - return -1; - } - - return mpd_isinfinite(MPD(v)); -} - -static int64_t -PyDec_GetDigits(const PyObject *v) -{ - if (!PyDec_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "PyDec_GetDigits: argument must be a Decimal"); - return -1; - } - - return MPD(v)->digits; -} - -static mpd_uint128_triple_t -PyDec_AsUint128Triple(const PyObject *v) -{ - if (!PyDec_Check(v)) { - mpd_uint128_triple_t triple = { MPD_TRIPLE_ERROR, 0, 0, 0, 0 }; - PyErr_SetString(PyExc_TypeError, - "PyDec_AsUint128Triple: argument must be a Decimal"); - return triple; - } - - return mpd_as_uint128_triple(MPD(v)); -} - -static PyObject * -PyDec_FromUint128Triple(const mpd_uint128_triple_t *triple) -{ - PyObject *context; - PyObject *result; - uint32_t status = 0; - - CURRENT_CONTEXT(context); - - result = dec_alloc(); - if (result == NULL) { - return NULL; - } - - if (mpd_from_uint128_triple(MPD(result), triple, &status) < 0) { - if (dec_addstatus(context, status)) { - Py_DECREF(result); - return NULL; - } - } - - return result; -} - -/* Advanced API */ -static PyObject * -PyDec_Alloc(void) -{ - return dec_alloc(); -} - -static mpd_t * -PyDec_Get(PyObject *v) -{ - if (!PyDec_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "PyDec_Get: argument must be a Decimal"); - return NULL; - } - - return MPD(v); -} - -static const mpd_t * -PyDec_GetConst(const PyObject *v) -{ - if (!PyDec_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "PyDec_GetConst: argument must be a Decimal"); - return NULL; - } - - return MPD(v); -} - -static void -destroy_api(PyObject *capsule) -{ - void *capi = PyCapsule_GetPointer(capsule, PyDec_CAPSULE_NAME); - PyMem_Free(capi); -} - -static PyObject * -init_api(void) -{ - void **_decimal_api = PyMem_Calloc(CPYTHON_DECIMAL_MAX_API, sizeof(void *)); - if (_decimal_api == NULL) { - PyErr_NoMemory(); - return NULL; - } - - /* Simple API */ - _decimal_api[PyDec_TypeCheck_INDEX] = (void *)PyDec_TypeCheck; - _decimal_api[PyDec_IsSpecial_INDEX] = (void *)PyDec_IsSpecial; - _decimal_api[PyDec_IsNaN_INDEX] = (void *)PyDec_IsNaN; - _decimal_api[PyDec_IsInfinite_INDEX] = (void *)PyDec_IsInfinite; - _decimal_api[PyDec_GetDigits_INDEX] = (void *)PyDec_GetDigits; - _decimal_api[PyDec_AsUint128Triple_INDEX] = (void *)PyDec_AsUint128Triple; - _decimal_api[PyDec_FromUint128Triple_INDEX] = (void *)PyDec_FromUint128Triple; - - /* Advanced API */ - _decimal_api[PyDec_Alloc_INDEX] = (void *)PyDec_Alloc; - _decimal_api[PyDec_Get_INDEX] = (void *)PyDec_Get; - _decimal_api[PyDec_GetConst_INDEX] = (void *)PyDec_GetConst; - - PyObject *capsule = PyCapsule_New(_decimal_api, PyDec_CAPSULE_NAME, destroy_api); - if (!capsule) { - PyMem_Free(_decimal_api); - } - return capsule; -} - - -/****************************************************************************/ -/* Module */ -/****************************************************************************/ - static PyMethodDef _decimal_methods [] = { { "getcontext", (PyCFunction)PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext}, @@ -5849,27 +5678,17 @@ PyInit__decimal(void) DecCondMap *cm; struct ssize_constmap *ssize_cm; struct int_constmap *int_cm; - static PyObject *capsule = NULL; - static int initialized = 0; int i; /* Init libmpdec */ - if (!initialized) { - mpd_traphandler = dec_traphandler; - mpd_mallocfunc = PyMem_Malloc; - mpd_reallocfunc = PyMem_Realloc; - mpd_callocfunc = mpd_callocfunc_em; - mpd_free = PyMem_Free; - mpd_setminalloc(_Py_DEC_MINALLOC); - - capsule = init_api(); - if (capsule == NULL) { - return NULL; - } + mpd_traphandler = dec_traphandler; + mpd_mallocfunc = PyMem_Malloc; + mpd_reallocfunc = PyMem_Realloc; + mpd_callocfunc = mpd_callocfunc_em; + mpd_free = PyMem_Free; + mpd_setminalloc(_Py_DEC_MINALLOC); - initialized = 1; - } /* Init external C-API functions */ _py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; @@ -6094,10 +5913,6 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddStringConstant(m, "__version__", "1.70")); CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version())); - /* Add capsule API */ - if (PyModule_AddObjectRef(m, "_API", capsule) < 0) { - goto error; - } return m; @@ -6121,7 +5936,6 @@ error: Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(m); /* GCOV_NOT_REACHED */ - Py_CLEAR(capsule); /* GCOV_NOT_REACHED */ return NULL; /* GCOV_NOT_REACHED */ } diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py index 88fd7b5..3726db1 100644 --- a/Modules/_decimal/tests/bench.py +++ b/Modules/_decimal/tests/bench.py @@ -7,10 +7,13 @@ import time +try: + from test.support import import_fresh_module +except ImportError: + from test.test_support import import_fresh_module -import _decimal as C -import _pydecimal as P - +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) # # NOTE: This is the pi function from the decimal documentation, modified diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py index 5de57d1..98ecd50 100644 --- a/Modules/_decimal/tests/deccheck.py +++ b/Modules/_decimal/tests/deccheck.py @@ -47,18 +47,14 @@ from subprocess import PIPE, STDOUT from queue import Queue, Empty from threading import Thread, Event, Lock +from test.support import import_fresh_module from randdec import randfloat, all_unary, all_binary, all_ternary from randdec import unary_optarg, binary_optarg, ternary_optarg from formathelper import rand_format, rand_locale from _pydecimal import _dec_from_triple -from _testcapi import decimal_as_triple -from _testcapi import decimal_from_triple - -import _decimal as C -import _pydecimal as P - - +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) EXIT_STATUS = 0 @@ -162,45 +158,6 @@ TernaryRestricted = ['__pow__', 'context.power'] # ====================================================================== -# Triple tests -# ====================================================================== - -def c_as_triple(dec): - sign, hi, lo, exp = decimal_as_triple(dec) - - coeff = hi * 2**64 + lo - return (sign, coeff, exp) - -def c_from_triple(triple): - sign, coeff, exp = triple - - hi = coeff // 2**64 - lo = coeff % 2**64 - return decimal_from_triple((sign, hi, lo, exp)) - -def p_as_triple(dec): - sign, digits, exp = dec.as_tuple() - - s = "".join(str(d) for d in digits) - coeff = int(s) if s else 0 - - if coeff < 0 or coeff >= 2**128: - raise ValueError("value out of bounds for a uint128 triple") - - return (sign, coeff, exp) - -def p_from_triple(triple): - sign, coeff, exp = triple - - if coeff < 0 or coeff >= 2**128: - raise ValueError("value out of bounds for a uint128 triple") - - digits = tuple(int(c) for c in str(coeff)) - - return P.Decimal((sign, digits, exp)) - - -# ====================================================================== # Unified Context # ====================================================================== @@ -893,44 +850,12 @@ def verify(t, stat): t.presults.append(str(t.rp.imag)) t.presults.append(str(t.rp.real)) - ctriple = None - if str(t.rc) == str(t.rp): # see skip handler - try: - ctriple = c_as_triple(t.rc) - except ValueError: - try: - ptriple = p_as_triple(t.rp) - except ValueError: - pass - else: - raise RuntimeError("ValueError not raised") - else: - cres = c_from_triple(ctriple) - t.cresults.append(ctriple) - t.cresults.append(str(cres)) - - ptriple = p_as_triple(t.rp) - pres = p_from_triple(ptriple) - t.presults.append(ptriple) - t.presults.append(str(pres)) - if t.with_maxcontext and isinstance(t.rmax, C.Decimal): t.maxresults.append(t.rmax.to_eng_string()) t.maxresults.append(t.rmax.as_tuple()) t.maxresults.append(str(t.rmax.imag)) t.maxresults.append(str(t.rmax.real)) - if ctriple is not None: - # NaN payloads etc. depend on precision and clamp. - if all_nan(t.rc) and all_nan(t.rmax): - t.maxresults.append(ctriple) - t.maxresults.append(str(cres)) - else: - maxtriple = c_as_triple(t.rmax) - maxres = c_from_triple(maxtriple) - t.maxresults.append(maxtriple) - t.maxresults.append(str(maxres)) - nc = t.rc.number_class().lstrip('+-s') stat[nc] += 1 else: diff --git a/Modules/_decimal/tests/formathelper.py b/Modules/_decimal/tests/formathelper.py index 482e02a..19b2aad 100644 --- a/Modules/_decimal/tests/formathelper.py +++ b/Modules/_decimal/tests/formathelper.py @@ -31,10 +31,11 @@ import os, sys, locale, random import platform, subprocess +from test.support import import_fresh_module from distutils.spawn import find_executable -import _decimal as C -import _pydecimal as P +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) windows_lang_strings = [ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ed59c32..20107f2 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -19,7 +19,6 @@ #include "Python.h" #include "datetime.h" -#include "pydecimal.h" #include "marshal.h" #include "structmember.h" // PyMemberDef #include <float.h> @@ -2764,252 +2763,6 @@ test_PyDateTime_DELTA_GET(PyObject *self, PyObject *obj) return Py_BuildValue("(lll)", days, seconds, microseconds); } -/* Test decimal API */ -static int decimal_initialized = 0; -static PyObject * -decimal_is_special(PyObject *module, PyObject *dec) -{ - int is_special; - - (void)module; - if (!decimal_initialized) { - if (import_decimal() < 0) { - return NULL; - } - - decimal_initialized = 1; - } - - is_special = PyDec_IsSpecial(dec); - if (is_special < 0) { - return NULL; - } - - return PyBool_FromLong(is_special); -} - -static PyObject * -decimal_is_nan(PyObject *module, PyObject *dec) -{ - int is_nan; - - (void)module; - if (!decimal_initialized) { - if (import_decimal() < 0) { - return NULL; - } - - decimal_initialized = 1; - } - - is_nan = PyDec_IsNaN(dec); - if (is_nan < 0) { - return NULL; - } - - return PyBool_FromLong(is_nan); -} - -static PyObject * -decimal_is_infinite(PyObject *module, PyObject *dec) -{ - int is_infinite; - - (void)module; - if (!decimal_initialized) { - if (import_decimal() < 0) { - return NULL; - } - - decimal_initialized = 1; - } - - is_infinite = PyDec_IsInfinite(dec); - if (is_infinite < 0) { - return NULL; - } - - return PyBool_FromLong(is_infinite); -} - -static PyObject * -decimal_get_digits(PyObject *module, PyObject *dec) -{ - int64_t digits; - - (void)module; - if (!decimal_initialized) { - if (import_decimal() < 0) { - return NULL; - } - - decimal_initialized = 1; - } - - digits = PyDec_GetDigits(dec); - if (digits < 0) { - return NULL; - } - - return PyLong_FromLongLong(digits); -} - -static PyObject * -decimal_as_triple(PyObject *module, PyObject *dec) -{ - PyObject *tuple = NULL; - PyObject *sign, *hi, *lo; - mpd_uint128_triple_t triple; - - (void)module; - if (!decimal_initialized) { - if (import_decimal() < 0) { - return NULL; - } - - decimal_initialized = 1; - } - - triple = PyDec_AsUint128Triple(dec); - if (triple.tag == MPD_TRIPLE_ERROR && PyErr_Occurred()) { - return NULL; - } - - sign = PyLong_FromUnsignedLong(triple.sign); - if (sign == NULL) { - return NULL; - } - - hi = PyLong_FromUnsignedLongLong(triple.hi); - if (hi == NULL) { - Py_DECREF(sign); - return NULL; - } - - lo = PyLong_FromUnsignedLongLong(triple.lo); - if (lo == NULL) { - Py_DECREF(hi); - Py_DECREF(sign); - return NULL; - } - - switch (triple.tag) { - case MPD_TRIPLE_QNAN: - assert(triple.exp == 0); - tuple = Py_BuildValue("(OOOs)", sign, hi, lo, "n"); - break; - - case MPD_TRIPLE_SNAN: - assert(triple.exp == 0); - tuple = Py_BuildValue("(OOOs)", sign, hi, lo, "N"); - break; - - case MPD_TRIPLE_INF: - assert(triple.hi == 0); - assert(triple.lo == 0); - assert(triple.exp == 0); - tuple = Py_BuildValue("(OOOs)", sign, hi, lo, "F"); - break; - - case MPD_TRIPLE_NORMAL: - tuple = Py_BuildValue("(OOOL)", sign, hi, lo, triple.exp); - break; - - case MPD_TRIPLE_ERROR: - PyErr_SetString(PyExc_ValueError, - "value out of bounds for a uint128 triple"); - break; - - default: - PyErr_SetString(PyExc_RuntimeError, - "decimal_as_triple: internal error: unexpected tag"); - break; - } - - Py_DECREF(lo); - Py_DECREF(hi); - Py_DECREF(sign); - - return tuple; -} - -static PyObject * -decimal_from_triple(PyObject *module, PyObject *tuple) -{ - mpd_uint128_triple_t triple = { MPD_TRIPLE_ERROR, 0, 0, 0, 0 }; - PyObject *exp; - unsigned long sign; - - (void)module; - if (!decimal_initialized) { - if (import_decimal() < 0) { - return NULL; - } - - decimal_initialized = 1; - } - - if (!PyTuple_Check(tuple)) { - PyErr_SetString(PyExc_TypeError, "argument must be a tuple"); - return NULL; - } - - if (PyTuple_GET_SIZE(tuple) != 4) { - PyErr_SetString(PyExc_ValueError, "tuple size must be 4"); - return NULL; - } - - sign = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(tuple, 0)); - if (sign == (unsigned long)-1 && PyErr_Occurred()) { - return NULL; - } - if (sign > UINT8_MAX) { - PyErr_SetString(PyExc_ValueError, "sign must be 0 or 1"); - return NULL; - } - triple.sign = (uint8_t)sign; - - triple.hi = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(tuple, 1)); - if (triple.hi == (unsigned long long)-1 && PyErr_Occurred()) { - return NULL; - } - - triple.lo = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(tuple, 2)); - if (triple.lo == (unsigned long long)-1 && PyErr_Occurred()) { - return NULL; - } - - exp = PyTuple_GET_ITEM(tuple, 3); - if (PyLong_Check(exp)) { - triple.tag = MPD_TRIPLE_NORMAL; - triple.exp = PyLong_AsLongLong(exp); - if (triple.exp == -1 && PyErr_Occurred()) { - return NULL; - } - } - else if (PyUnicode_Check(exp)) { - if (PyUnicode_CompareWithASCIIString(exp, "F") == 0) { - triple.tag = MPD_TRIPLE_INF; - } - else if (PyUnicode_CompareWithASCIIString(exp, "n") == 0) { - triple.tag = MPD_TRIPLE_QNAN; - } - else if (PyUnicode_CompareWithASCIIString(exp, "N") == 0) { - triple.tag = MPD_TRIPLE_SNAN; - } - else { - PyErr_SetString(PyExc_ValueError, "not a valid exponent"); - return NULL; - } - } - else { - PyErr_SetString(PyExc_TypeError, "exponent must be int or string"); - return NULL; - } - - return PyDec_FromUint128Triple(&triple); -} - /* test_thread_state spawns a thread of its own, and that thread releases * `thread_done` when it's finished. The driver code has to know when the * thread finishes, because the thread uses a PyObject (the callable) that @@ -5725,12 +5478,6 @@ static PyMethodDef TestMethods[] = { {"PyDateTime_DATE_GET", test_PyDateTime_DATE_GET, METH_O}, {"PyDateTime_TIME_GET", test_PyDateTime_TIME_GET, METH_O}, {"PyDateTime_DELTA_GET", test_PyDateTime_DELTA_GET, METH_O}, - {"decimal_is_special", decimal_is_special, METH_O}, - {"decimal_is_nan", decimal_is_nan, METH_O}, - {"decimal_is_infinite", decimal_is_infinite, METH_O}, - {"decimal_get_digits", decimal_get_digits, METH_O}, - {"decimal_as_triple", decimal_as_triple, METH_O}, - {"decimal_from_triple", decimal_from_triple, METH_O}, {"test_list_api", test_list_api, METH_NOARGS}, {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, {"dict_getitem_knownhash", dict_getitem_knownhash, METH_VARARGS}, |