]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-73487: Convert ``_decimal`` to use Argument Clinic (part 2) (#137637)
authorSergey B Kirpichev <skirpichev@gmail.com>
Mon, 18 Aug 2025 13:21:00 +0000 (16:21 +0300)
committerGitHub <noreply@github.com>
Mon, 18 Aug 2025 13:21:00 +0000 (14:21 +0100)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Include/internal/pycore_global_objects_fini_generated.h
Include/internal/pycore_global_strings.h
Include/internal/pycore_runtime_init_generated.h
Include/internal/pycore_unicodeobject_generated.h
Modules/_decimal/_decimal.c
Modules/_decimal/clinic/_decimal.c.h
Modules/_decimal/docstrings.h

index 27102588076cc2838e0acc24af7f8f114ec5e740..c5a08e05e7028705fd2d92ee5f5fa2302ca6578c 100644 (file)
@@ -566,6 +566,8 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CANCELLED));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(Emax));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(Emin));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(FINISHED));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(False));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(JSONDecodeError));
@@ -848,11 +850,13 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(callback));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cancel));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(capath));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(capitals));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(category));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cb_type));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(certfile));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(chain));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(check_same_thread));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(clamp));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(clear));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(close));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(closed));
@@ -892,6 +896,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(coro));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(count));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(covariant));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ctx));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cwd));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(d_parameter_type));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(data));
@@ -1113,6 +1118,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(module));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(module_globals));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(modules));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(modulo));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(month));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mro));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(msg));
@@ -1181,6 +1187,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos1));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pos2));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(posix));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(prec));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(preserve_exc));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(print_file_and_line));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(priority));
@@ -1303,6 +1310,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(traceback));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trailers));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(translate));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(traps));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(true));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(truncate));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(twice));
index 2d6130c216993f49dbc9a666f95ae447898d1a01..9e49e4497750a0eed0d74b23d600846d1f66e6fd 100644 (file)
@@ -57,6 +57,8 @@ struct _Py_global_strings {
 
     struct {
         STRUCT_FOR_ID(CANCELLED)
+        STRUCT_FOR_ID(Emax)
+        STRUCT_FOR_ID(Emin)
         STRUCT_FOR_ID(FINISHED)
         STRUCT_FOR_ID(False)
         STRUCT_FOR_ID(JSONDecodeError)
@@ -339,11 +341,13 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(callback)
         STRUCT_FOR_ID(cancel)
         STRUCT_FOR_ID(capath)
+        STRUCT_FOR_ID(capitals)
         STRUCT_FOR_ID(category)
         STRUCT_FOR_ID(cb_type)
         STRUCT_FOR_ID(certfile)
         STRUCT_FOR_ID(chain)
         STRUCT_FOR_ID(check_same_thread)
+        STRUCT_FOR_ID(clamp)
         STRUCT_FOR_ID(clear)
         STRUCT_FOR_ID(close)
         STRUCT_FOR_ID(closed)
@@ -383,6 +387,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(coro)
         STRUCT_FOR_ID(count)
         STRUCT_FOR_ID(covariant)
+        STRUCT_FOR_ID(ctx)
         STRUCT_FOR_ID(cwd)
         STRUCT_FOR_ID(d_parameter_type)
         STRUCT_FOR_ID(data)
@@ -604,6 +609,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(module)
         STRUCT_FOR_ID(module_globals)
         STRUCT_FOR_ID(modules)
+        STRUCT_FOR_ID(modulo)
         STRUCT_FOR_ID(month)
         STRUCT_FOR_ID(mro)
         STRUCT_FOR_ID(msg)
@@ -672,6 +678,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(pos1)
         STRUCT_FOR_ID(pos2)
         STRUCT_FOR_ID(posix)
+        STRUCT_FOR_ID(prec)
         STRUCT_FOR_ID(preserve_exc)
         STRUCT_FOR_ID(print_file_and_line)
         STRUCT_FOR_ID(priority)
@@ -794,6 +801,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(traceback)
         STRUCT_FOR_ID(trailers)
         STRUCT_FOR_ID(translate)
+        STRUCT_FOR_ID(traps)
         STRUCT_FOR_ID(true)
         STRUCT_FOR_ID(truncate)
         STRUCT_FOR_ID(twice)
index 9e72c7df77b945f97b632a4258fe70c29e1124dd..5c65cb218dedbbef0d350acbb8295f2cb8fbb3f1 100644 (file)
@@ -564,6 +564,8 @@ extern "C" {
 
 #define _Py_str_identifiers_INIT { \
     INIT_ID(CANCELLED), \
+    INIT_ID(Emax), \
+    INIT_ID(Emin), \
     INIT_ID(FINISHED), \
     INIT_ID(False), \
     INIT_ID(JSONDecodeError), \
@@ -846,11 +848,13 @@ extern "C" {
     INIT_ID(callback), \
     INIT_ID(cancel), \
     INIT_ID(capath), \
+    INIT_ID(capitals), \
     INIT_ID(category), \
     INIT_ID(cb_type), \
     INIT_ID(certfile), \
     INIT_ID(chain), \
     INIT_ID(check_same_thread), \
+    INIT_ID(clamp), \
     INIT_ID(clear), \
     INIT_ID(close), \
     INIT_ID(closed), \
@@ -890,6 +894,7 @@ extern "C" {
     INIT_ID(coro), \
     INIT_ID(count), \
     INIT_ID(covariant), \
+    INIT_ID(ctx), \
     INIT_ID(cwd), \
     INIT_ID(d_parameter_type), \
     INIT_ID(data), \
@@ -1111,6 +1116,7 @@ extern "C" {
     INIT_ID(module), \
     INIT_ID(module_globals), \
     INIT_ID(modules), \
+    INIT_ID(modulo), \
     INIT_ID(month), \
     INIT_ID(mro), \
     INIT_ID(msg), \
@@ -1179,6 +1185,7 @@ extern "C" {
     INIT_ID(pos1), \
     INIT_ID(pos2), \
     INIT_ID(posix), \
+    INIT_ID(prec), \
     INIT_ID(preserve_exc), \
     INIT_ID(print_file_and_line), \
     INIT_ID(priority), \
@@ -1301,6 +1308,7 @@ extern "C" {
     INIT_ID(traceback), \
     INIT_ID(trailers), \
     INIT_ID(translate), \
+    INIT_ID(traps), \
     INIT_ID(true), \
     INIT_ID(truncate), \
     INIT_ID(twice), \
index 02c62f68ff08017178cf7d876e29416b5a3df076..4905007b95f8fa1dbcdab9ff15b9297dc873cecc 100644 (file)
@@ -16,6 +16,14 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(Emax);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(Emin);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(FINISHED);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -1144,6 +1152,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(capitals);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(category);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -1164,6 +1176,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(clamp);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(clear);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -1320,6 +1336,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(ctx);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(cwd);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -2204,6 +2224,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(modulo);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(month);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -2476,6 +2500,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(prec);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(preserve_exc);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -2964,6 +2992,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(traps);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(true);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
index 46cedf83df1f00c453244ca5edc9ae5bf4d4c3e0..52ed5a532efd27816bf9f621e2f60db11df068ef 100644 (file)
@@ -63,8 +63,9 @@
 /*[clinic input]
 module _decimal
 class _decimal.Decimal "PyObject *" "&dec_spec"
+class _decimal.Context "PyObject *" "&ctx_spec"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e0e1f68f1f413f5f]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8c3aa7cfde934d7b]*/
 
 struct PyDecContextObject;
 struct DecCondMap;
@@ -1566,17 +1567,26 @@ init_extended_context(PyObject *v)
 }
 
 /* Factory function for creating IEEE interchange format contexts */
+
+/*[clinic input]
+_decimal.IEEEContext
+
+    bits: Py_ssize_t
+    /
+
+Return a context, initialized as one of the IEEE interchange formats.
+
+The argument must be a multiple of 32 and less than
+IEEE_CONTEXT_MAX_BITS.
+[clinic start generated code]*/
+
 static PyObject *
-ieee_context(PyObject *module, PyObject *v)
+_decimal_IEEEContext_impl(PyObject *module, Py_ssize_t bits)
+/*[clinic end generated code: output=19a35f320fe19789 input=5cff864d899eb2d7]*/
 {
     PyObject *context;
-    mpd_ssize_t bits;
     mpd_context_t ctx;
 
-    bits = PyLong_AsSsize_t(v);
-    if (bits == -1 && PyErr_Occurred()) {
-        return NULL;
-    }
     if (bits <= 0 || bits > INT_MAX) {
         goto error;
     }
@@ -1775,7 +1785,7 @@ current_context(decimal_state *modstate)
 
 /* Return a new reference to the current context */
 static PyObject *
-PyDec_GetCurrentContext(PyObject *self, PyObject *Py_UNUSED(dummy))
+PyDec_GetCurrentContext(PyObject *self)
 {
     PyObject *context;
     decimal_state *state = get_module_state(self);
@@ -1871,7 +1881,7 @@ current_context(decimal_state *state)
 
 /* Return a new reference to the current context */
 static PyObject *
-PyDec_GetCurrentContext(PyObject *self, PyObject *Py_UNUSED(dummy))
+PyDec_GetCurrentContext(PyObject *self)
 {
     decimal_state *state = get_module_state(self);
     return current_context(state);
@@ -1910,36 +1920,73 @@ PyDec_SetCurrentContext(PyObject *self, PyObject *v)
 }
 #endif
 
+/*[clinic input]
+_decimal.getcontext
+
+Get the current default context.
+[clinic start generated code]*/
+
+static PyObject *
+_decimal_getcontext_impl(PyObject *module)
+/*[clinic end generated code: output=5982062c4d39e3dd input=7ac316fe42a1b6f5]*/
+{
+    return PyDec_GetCurrentContext(module);
+}
+
+/*[clinic input]
+_decimal.setcontext
+
+    context: object
+    /
+
+Set a new default context.
+[clinic start generated code]*/
+
+static PyObject *
+_decimal_setcontext(PyObject *module, PyObject *context)
+/*[clinic end generated code: output=8065f870be2852ce input=b57d7ee786b022a6]*/
+{
+    return PyDec_SetCurrentContext(module, context);
+}
+
 /* Context manager object for the 'with' statement. The manager
  * owns one reference to the global (outer) context and one
  * to the local (inner) context. */
+
+/*[clinic input]
+@text_signature "($module, /, ctx=None, **kwargs)"
+_decimal.localcontext
+
+    ctx as local: object = None
+    *
+    prec: object = None
+    rounding: object = None
+    Emin: object = None
+    Emax: object = None
+    capitals: object = None
+    clamp: object = None
+    flags: object = None
+    traps: object = None
+
+Return a context manager for a copy of the supplied context.
+
+That will set the default context to a copy of ctx on entry to the
+with-statement and restore the previous default context when exiting
+the with-statement. If no context is specified, a copy of the current
+default context is used.
+[clinic start generated code]*/
+
 static PyObject *
-ctxmanager_new(PyObject *m, PyObject *args, PyObject *kwds)
+_decimal_localcontext_impl(PyObject *module, PyObject *local, PyObject *prec,
+                           PyObject *rounding, PyObject *Emin,
+                           PyObject *Emax, PyObject *capitals,
+                           PyObject *clamp, PyObject *flags, PyObject *traps)
+/*[clinic end generated code: output=9bf4e47742a809b0 input=490307b9689c3856]*/
 {
-    static char *kwlist[] = {
-      "ctx", "prec", "rounding",
-      "Emin", "Emax", "capitals",
-      "clamp", "flags", "traps",
-      NULL
-    };
-    PyObject *local = Py_None;
     PyObject *global;
 
-    PyObject *prec = Py_None;
-    PyObject *rounding = Py_None;
-    PyObject *Emin = Py_None;
-    PyObject *Emax = Py_None;
-    PyObject *capitals = Py_None;
-    PyObject *clamp = Py_None;
-    PyObject *flags = Py_None;
-    PyObject *traps = Py_None;
-
-    decimal_state *state = get_module_state(m);
+    decimal_state *state = get_module_state(module);
     CURRENT_CONTEXT(state, global);
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOOOO", kwlist, &local,
-          &prec, &rounding, &Emin, &Emax, &capitals, &clamp, &flags, &traps)) {
-        return NULL;
-    }
     if (local == Py_None) {
         local = global;
     }
@@ -3569,15 +3616,27 @@ pydec_format(PyObject *dec, PyObject *context, PyObject *fmt, decimal_state *sta
 }
 
 /* Formatted representation of a PyDecObject. */
+
+/*[clinic input]
+_decimal.Decimal.__format__
+
+    self as dec: self
+    format_spec as fmtarg: unicode
+    override: object = NULL
+    /
+
+Formats the Decimal according to format_spec.
+[clinic start generated code]*/
+
 static PyObject *
-dec_format(PyObject *dec, PyObject *args)
+_decimal_Decimal___format___impl(PyObject *dec, PyObject *fmtarg,
+                                 PyObject *override)
+/*[clinic end generated code: output=4b3640b7f0c8b6a5 input=e53488e49a0fff00]*/
 {
     PyObject *result = NULL;
-    PyObject *override = NULL;
     PyObject *dot = NULL;
     PyObject *sep = NULL;
     PyObject *grouping = NULL;
-    PyObject *fmtarg;
     PyObject *context;
     mpd_spec_t spec;
     char *fmt;
@@ -3585,42 +3644,29 @@ dec_format(PyObject *dec, PyObject *args)
     uint32_t status = 0;
     int replace_fillchar = 0;
     Py_ssize_t size;
-
-
     decimal_state *state = get_module_state_by_def(Py_TYPE(dec));
     CURRENT_CONTEXT(state, context);
-    if (!PyArg_ParseTuple(args, "O|O", &fmtarg, &override)) {
+    fmt = (char *)PyUnicode_AsUTF8AndSize(fmtarg, &size);
+    if (fmt == NULL) {
         return NULL;
     }
 
-    if (PyUnicode_Check(fmtarg)) {
-        fmt = (char *)PyUnicode_AsUTF8AndSize(fmtarg, &size);
-        if (fmt == NULL) {
+    if (size > 0 && fmt[size-1] == 'N') {
+        if (PyErr_WarnEx(PyExc_DeprecationWarning,
+                         "Format specifier 'N' is deprecated", 1) < 0) {
             return NULL;
         }
+    }
 
-        if (size > 0 && fmt[size-1] == 'N') {
-            if (PyErr_WarnEx(PyExc_DeprecationWarning,
-                             "Format specifier 'N' is deprecated", 1) < 0) {
-                return NULL;
-            }
-        }
-
-        if (size > 0 && fmt[0] == '\0') {
-            /* NUL fill character: must be replaced with a valid UTF-8 char
-               before calling mpd_parse_fmt_str(). */
-            replace_fillchar = 1;
-            fmt = dec_strdup(fmt, size);
-            if (fmt == NULL) {
-                return NULL;
-            }
-            fmt[0] = '_';
+    if (size > 0 && fmt[0] == '\0') {
+        /* NUL fill character: must be replaced with a valid UTF-8 char
+           before calling mpd_parse_fmt_str(). */
+        replace_fillchar = 1;
+        fmt = dec_strdup(fmt, size);
+        if (fmt == NULL) {
+            return NULL;
         }
-    }
-    else {
-        PyErr_SetString(PyExc_TypeError,
-            "format arg must be str");
-        return NULL;
+        fmt[0] = '_';
     }
 
     if (!mpd_parse_fmt_str(&spec, fmt, CtxCaps(context))) {
@@ -5389,7 +5435,7 @@ static PyMethodDef dec_methods [] =
   /* Special methods */
   { "__copy__", dec_copy, METH_NOARGS, NULL },
   { "__deepcopy__", dec_copy, METH_O, NULL },
-  { "__format__", dec_format, METH_VARARGS, NULL },
+  _DECIMAL_DECIMAL___FORMAT___METHODDEF
   { "__reduce__", dec_reduce, METH_NOARGS, NULL },
   { "__round__", PyDec_Round, METH_VARARGS, NULL },
   { "__ceil__", dec_ceil, METH_NOARGS, NULL },
@@ -5686,20 +5732,41 @@ ctx_mpd_qdivmod(PyObject *context, PyObject *args)
 }
 
 /* Binary or ternary arithmetic functions */
+
+/*[clinic input]
+_decimal.Context.power
+
+    self as context: self
+    a as base: object
+    b as exp: object
+    modulo as mod: object = None
+
+Compute a**b.
+
+If 'a' is negative, then 'b' must be integral. The result will be
+inexact unless 'a' is integral and the result is finite and can be
+expressed exactly in 'precision' digits.  In the Python version the
+result is always correctly rounded, in the C version the result is
+almost always correctly rounded.
+
+If modulo is given, compute (a**b) % modulo. The following
+restrictions hold:
+
+    * all three arguments must be integral
+    * 'b' must be nonnegative
+    * at least one of 'a' or 'b' must be nonzero
+    * modulo must be nonzero and less than 10**prec in absolute value
+[clinic start generated code]*/
+
 static PyObject *
-ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds)
+_decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp,
+                            PyObject *mod)
+/*[clinic end generated code: output=d2e68694ec545245 input=e9aef844813de243]*/
 {
-    static char *kwlist[] = {"a", "b", "modulo", NULL};
-    PyObject *base, *exp, *mod = Py_None;
     PyObject *a, *b, *c = NULL;
     PyObject *result;
     uint32_t status = 0;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist,
-                                     &base, &exp, &mod)) {
-        return NULL;
-    }
-
     CONVERT_BINOP_RAISE(&a, &b, base, exp, context);
 
     if (mod != Py_None) {
@@ -6020,7 +6087,7 @@ static PyMethodDef context_methods [] =
   { "subtract", ctx_mpd_qsub, METH_VARARGS, doc_ctx_subtract },
 
   /* Binary or ternary arithmetic functions */
-  { "power", _PyCFunction_CAST(ctx_mpd_qpow), METH_VARARGS|METH_KEYWORDS, doc_ctx_power },
+  _DECIMAL_CONTEXT_POWER_METHODDEF
 
   /* Ternary arithmetic functions */
   { "fma", ctx_mpd_qfma, METH_VARARGS, doc_ctx_fma },
@@ -6117,10 +6184,10 @@ static PyType_Spec context_spec = {
 
 static PyMethodDef _decimal_methods [] =
 {
-  { "getcontext", PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext},
-  { "setcontext", PyDec_SetCurrentContext, METH_O, doc_setcontext},
-  { "localcontext", _PyCFunction_CAST(ctxmanager_new), METH_VARARGS|METH_KEYWORDS, doc_localcontext},
-  { "IEEEContext", ieee_context, METH_O, doc_ieee_context},
+  _DECIMAL_GETCONTEXT_METHODDEF
+  _DECIMAL_SETCONTEXT_METHODDEF
+  _DECIMAL_LOCALCONTEXT_METHODDEF
+  _DECIMAL_IEEECONTEXT_METHODDEF
   { NULL, NULL, 1, NULL }
 };
 
index 441515edbf60f6f9a33c5469f187d151d7522f69..7a2bcce1e9316b06af3594f4c71c077f2312f3fa 100644 (file)
@@ -6,8 +6,206 @@ preserve
 #  include "pycore_gc.h"          // PyGC_Head
 #  include "pycore_runtime.h"     // _Py_ID()
 #endif
+#include "pycore_abstract.h"      // _PyNumber_Index()
 #include "pycore_modsupport.h"    // _PyArg_UnpackKeywords()
 
+PyDoc_STRVAR(_decimal_IEEEContext__doc__,
+"IEEEContext($module, bits, /)\n"
+"--\n"
+"\n"
+"Return a context, initialized as one of the IEEE interchange formats.\n"
+"\n"
+"The argument must be a multiple of 32 and less than\n"
+"IEEE_CONTEXT_MAX_BITS.");
+
+#define _DECIMAL_IEEECONTEXT_METHODDEF    \
+    {"IEEEContext", (PyCFunction)_decimal_IEEEContext, METH_O, _decimal_IEEEContext__doc__},
+
+static PyObject *
+_decimal_IEEEContext_impl(PyObject *module, Py_ssize_t bits);
+
+static PyObject *
+_decimal_IEEEContext(PyObject *module, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    Py_ssize_t bits;
+
+    {
+        Py_ssize_t ival = -1;
+        PyObject *iobj = _PyNumber_Index(arg);
+        if (iobj != NULL) {
+            ival = PyLong_AsSsize_t(iobj);
+            Py_DECREF(iobj);
+        }
+        if (ival == -1 && PyErr_Occurred()) {
+            goto exit;
+        }
+        bits = ival;
+    }
+    return_value = _decimal_IEEEContext_impl(module, bits);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_decimal_getcontext__doc__,
+"getcontext($module, /)\n"
+"--\n"
+"\n"
+"Get the current default context.");
+
+#define _DECIMAL_GETCONTEXT_METHODDEF    \
+    {"getcontext", (PyCFunction)_decimal_getcontext, METH_NOARGS, _decimal_getcontext__doc__},
+
+static PyObject *
+_decimal_getcontext_impl(PyObject *module);
+
+static PyObject *
+_decimal_getcontext(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _decimal_getcontext_impl(module);
+}
+
+PyDoc_STRVAR(_decimal_setcontext__doc__,
+"setcontext($module, context, /)\n"
+"--\n"
+"\n"
+"Set a new default context.");
+
+#define _DECIMAL_SETCONTEXT_METHODDEF    \
+    {"setcontext", (PyCFunction)_decimal_setcontext, METH_O, _decimal_setcontext__doc__},
+
+PyDoc_STRVAR(_decimal_localcontext__doc__,
+"localcontext($module, /, ctx=None, **kwargs)\n"
+"--\n"
+"\n"
+"Return a context manager for a copy of the supplied context.\n"
+"\n"
+"That will set the default context to a copy of ctx on entry to the\n"
+"with-statement and restore the previous default context when exiting\n"
+"the with-statement. If no context is specified, a copy of the current\n"
+"default context is used.");
+
+#define _DECIMAL_LOCALCONTEXT_METHODDEF    \
+    {"localcontext", _PyCFunction_CAST(_decimal_localcontext), METH_FASTCALL|METH_KEYWORDS, _decimal_localcontext__doc__},
+
+static PyObject *
+_decimal_localcontext_impl(PyObject *module, PyObject *local, PyObject *prec,
+                           PyObject *rounding, PyObject *Emin,
+                           PyObject *Emax, PyObject *capitals,
+                           PyObject *clamp, PyObject *flags, PyObject *traps);
+
+static PyObject *
+_decimal_localcontext(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 9
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(ctx), &_Py_ID(prec), &_Py_ID(rounding), &_Py_ID(Emin), &_Py_ID(Emax), &_Py_ID(capitals), &_Py_ID(clamp), &_Py_ID(flags), &_Py_ID(traps), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"ctx", "prec", "rounding", "Emin", "Emax", "capitals", "clamp", "flags", "traps", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "localcontext",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[9];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
+    PyObject *local = Py_None;
+    PyObject *prec = Py_None;
+    PyObject *rounding = Py_None;
+    PyObject *Emin = Py_None;
+    PyObject *Emax = Py_None;
+    PyObject *capitals = Py_None;
+    PyObject *clamp = Py_None;
+    PyObject *flags = Py_None;
+    PyObject *traps = Py_None;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    if (args[0]) {
+        local = args[0];
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+skip_optional_pos:
+    if (!noptargs) {
+        goto skip_optional_kwonly;
+    }
+    if (args[1]) {
+        prec = args[1];
+        if (!--noptargs) {
+            goto skip_optional_kwonly;
+        }
+    }
+    if (args[2]) {
+        rounding = args[2];
+        if (!--noptargs) {
+            goto skip_optional_kwonly;
+        }
+    }
+    if (args[3]) {
+        Emin = args[3];
+        if (!--noptargs) {
+            goto skip_optional_kwonly;
+        }
+    }
+    if (args[4]) {
+        Emax = args[4];
+        if (!--noptargs) {
+            goto skip_optional_kwonly;
+        }
+    }
+    if (args[5]) {
+        capitals = args[5];
+        if (!--noptargs) {
+            goto skip_optional_kwonly;
+        }
+    }
+    if (args[6]) {
+        clamp = args[6];
+        if (!--noptargs) {
+            goto skip_optional_kwonly;
+        }
+    }
+    if (args[7]) {
+        flags = args[7];
+        if (!--noptargs) {
+            goto skip_optional_kwonly;
+        }
+    }
+    traps = args[8];
+skip_optional_kwonly:
+    return_value = _decimal_localcontext_impl(module, local, prec, rounding, Emin, Emax, capitals, clamp, flags, traps);
+
+exit:
+    return return_value;
+}
+
 PyDoc_STRVAR(_decimal_Decimal_from_float__doc__,
 "from_float($type, f, /)\n"
 "--\n"
@@ -71,6 +269,45 @@ _decimal_Decimal_from_number(PyObject *type, PyObject *number)
     return return_value;
 }
 
+PyDoc_STRVAR(_decimal_Decimal___format____doc__,
+"__format__($self, format_spec, override=<unrepresentable>, /)\n"
+"--\n"
+"\n"
+"Formats the Decimal according to format_spec.");
+
+#define _DECIMAL_DECIMAL___FORMAT___METHODDEF    \
+    {"__format__", _PyCFunction_CAST(_decimal_Decimal___format__), METH_FASTCALL, _decimal_Decimal___format____doc__},
+
+static PyObject *
+_decimal_Decimal___format___impl(PyObject *dec, PyObject *fmtarg,
+                                 PyObject *override);
+
+static PyObject *
+_decimal_Decimal___format__(PyObject *dec, PyObject *const *args, Py_ssize_t nargs)
+{
+    PyObject *return_value = NULL;
+    PyObject *fmtarg;
+    PyObject *override = NULL;
+
+    if (!_PyArg_CheckPositional("__format__", nargs, 1, 2)) {
+        goto exit;
+    }
+    if (!PyUnicode_Check(args[0])) {
+        _PyArg_BadArgument("__format__", "argument 1", "str", args[0]);
+        goto exit;
+    }
+    fmtarg = args[0];
+    if (nargs < 2) {
+        goto skip_optional;
+    }
+    override = args[1];
+skip_optional:
+    return_value = _decimal_Decimal___format___impl(dec, fmtarg, override);
+
+exit:
+    return return_value;
+}
+
 PyDoc_STRVAR(_decimal_Decimal_as_integer_ratio__doc__,
 "as_integer_ratio($self, /)\n"
 "--\n"
@@ -846,4 +1083,86 @@ skip_optional_pos:
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=f33166d1bf53e613 input=a9049054013a1b77]*/
+
+PyDoc_STRVAR(_decimal_Context_power__doc__,
+"power($self, /, a, b, modulo=None)\n"
+"--\n"
+"\n"
+"Compute a**b.\n"
+"\n"
+"If \'a\' is negative, then \'b\' must be integral. The result will be\n"
+"inexact unless \'a\' is integral and the result is finite and can be\n"
+"expressed exactly in \'precision\' digits.  In the Python version the\n"
+"result is always correctly rounded, in the C version the result is\n"
+"almost always correctly rounded.\n"
+"\n"
+"If modulo is given, compute (a**b) % modulo. The following\n"
+"restrictions hold:\n"
+"\n"
+"    * all three arguments must be integral\n"
+"    * \'b\' must be nonnegative\n"
+"    * at least one of \'a\' or \'b\' must be nonzero\n"
+"    * modulo must be nonzero and less than 10**prec in absolute value");
+
+#define _DECIMAL_CONTEXT_POWER_METHODDEF    \
+    {"power", _PyCFunction_CAST(_decimal_Context_power), METH_FASTCALL|METH_KEYWORDS, _decimal_Context_power__doc__},
+
+static PyObject *
+_decimal_Context_power_impl(PyObject *context, PyObject *base, PyObject *exp,
+                            PyObject *mod);
+
+static PyObject *
+_decimal_Context_power(PyObject *context, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 3
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { _Py_LATIN1_CHR('a'), _Py_LATIN1_CHR('b'), &_Py_ID(modulo), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"a", "b", "modulo", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "power",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[3];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2;
+    PyObject *base;
+    PyObject *exp;
+    PyObject *mod = Py_None;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 2, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    base = args[0];
+    exp = args[1];
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    mod = args[2];
+skip_optional_pos:
+    return_value = _decimal_Context_power_impl(context, base, exp, mod);
+
+exit:
+    return return_value;
+}
+/*[clinic end generated code: output=6bb5c926552c2760 input=a9049054013a1b77]*/
index bd1c1d5295d717f31450ae5b675b7c0022b32e32..3ecfd34122ab6b1f318cb7838efbc444349a12cb 100644 (file)
 PyDoc_STRVAR(doc__decimal,
 "C decimal arithmetic module");
 
-PyDoc_STRVAR(doc_getcontext,
-"getcontext($module, /)\n--\n\n\
-Get the current default context.\n\
-\n");
-
-PyDoc_STRVAR(doc_setcontext,
-"setcontext($module, context, /)\n--\n\n\
-Set a new default context.\n\
-\n");
-
-PyDoc_STRVAR(doc_localcontext,
-"localcontext($module, /, ctx=None, **kwargs)\n--\n\n\
-Return a context manager that will set the default context to a copy of ctx\n\
-on entry to the with-statement and restore the previous default context when\n\
-exiting the with-statement. If no context is specified, a copy of the current\n\
-default context is used.\n\
-\n");
-
-PyDoc_STRVAR(doc_ieee_context,
-"IEEEContext($module, bits, /)\n--\n\n\
-Return a context object initialized to the proper values for one of the\n\
-IEEE interchange formats.  The argument must be a multiple of 32 and less\n\
-than IEEE_CONTEXT_MAX_BITS.\n\
-\n");
-
-
 /******************************************************************************/
 /*                       Decimal Object and Methods                           */
 /******************************************************************************/
@@ -619,24 +593,6 @@ Plus corresponds to the unary prefix plus operator in Python, but applies\n\
 the context to the result.\n\
 \n");
 
-PyDoc_STRVAR(doc_ctx_power,
-"power($self, /, a, b, modulo=None)\n--\n\n\
-Compute a**b. If 'a' is negative, then 'b' must be integral. The result\n\
-will be inexact unless 'a' is integral and the result is finite and can\n\
-be expressed exactly in 'precision' digits.  In the Python version the\n\
-result is always correctly rounded, in the C version the result is almost\n\
-always correctly rounded.\n\
-\n\
-If modulo is given, compute (a**b) % modulo. The following restrictions\n\
-hold:\n\
-\n\
-    * all three arguments must be integral\n\
-    * 'b' must be nonnegative\n\
-    * at least one of 'a' or 'b' must be nonzero\n\
-    * modulo must be nonzero and less than 10**prec in absolute value\n\
-\n\
-\n");
-
 PyDoc_STRVAR(doc_ctx_quantize,
 "quantize($self, x, y, /)\n--\n\n\
 Return a value equal to x (rounded), having the exponent of y.\n\