Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Objects/interpolationobject.c
Line
Count
Source (jump to first uncovered line)
1
/* t-string Interpolation object implementation */
2
3
#include "Python.h"
4
#include "pycore_initconfig.h"    // _PyStatus_OK
5
#include "pycore_interpolation.h"
6
#include "pycore_typeobject.h"    // _PyType_GetDict
7
8
static int
9
_conversion_converter(PyObject *arg, PyObject **conversion)
10
0
{
11
0
    if (arg == Py_None) {
12
0
        return 1;
13
0
    }
14
15
0
    if (!PyUnicode_Check(arg)) {
16
0
        PyErr_Format(PyExc_TypeError,
17
0
            "Interpolation() argument 'conversion' must be str, not %T",
18
0
            arg);
19
0
        return 0;
20
0
    }
21
22
0
    Py_ssize_t len;
23
0
    const char *conv_str = PyUnicode_AsUTF8AndSize(arg, &len);
24
0
    if (len != 1 || !(conv_str[0] == 'a' || conv_str[0] == 'r' || conv_str[0] == 's')) {
25
0
        PyErr_SetString(PyExc_ValueError,
26
0
            "Interpolation() argument 'conversion' must be one of 's', 'a' or 'r'");
27
0
        return 0;
28
0
    }
29
30
0
    *conversion = arg;
31
0
    return 1;
32
0
}
33
34
#include "clinic/interpolationobject.c.h"
35
36
/*[clinic input]
37
class Interpolation "interpolationobject *" "&_PyInterpolation_Type"
38
[clinic start generated code]*/
39
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=161c64a16f9c4544]*/
40
41
typedef struct {
42
    PyObject_HEAD
43
    PyObject *value;
44
    PyObject *expression;
45
    PyObject *conversion;
46
    PyObject *format_spec;
47
} interpolationobject;
48
49
#define interpolationobject_CAST(op) \
50
0
    (assert(_PyInterpolation_CheckExact(op)), _Py_CAST(interpolationobject*, (op)))
51
52
/*[clinic input]
53
@classmethod
54
Interpolation.__new__ as interpolation_new
55
56
    value: object
57
    expression: object(subclass_of='&PyUnicode_Type')
58
    conversion: object(converter='_conversion_converter') = None
59
    format_spec: object(subclass_of='&PyUnicode_Type', c_default='&_Py_STR(empty)') = ""
60
[clinic start generated code]*/
61
62
static PyObject *
63
interpolation_new_impl(PyTypeObject *type, PyObject *value,
64
                       PyObject *expression, PyObject *conversion,
65
                       PyObject *format_spec)
66
/*[clinic end generated code: output=6488e288765bc1a9 input=d91711024068528c]*/
67
0
{
68
0
    interpolationobject *self = PyObject_GC_New(interpolationobject, type);
69
0
    if (!self) {
70
0
        return NULL;
71
0
    }
72
73
0
    self->value = Py_NewRef(value);
74
0
    self->expression = Py_NewRef(expression);
75
0
    self->conversion = Py_NewRef(conversion);
76
0
    self->format_spec = Py_NewRef(format_spec);
77
0
    PyObject_GC_Track(self);
78
0
    return (PyObject *) self;
79
0
}
80
81
static void
82
interpolation_dealloc(PyObject *op)
83
0
{
84
0
    PyObject_GC_UnTrack(op);
85
0
    Py_TYPE(op)->tp_clear(op);
86
0
    Py_TYPE(op)->tp_free(op);
87
0
}
88
89
static int
90
interpolation_clear(PyObject *op)
91
0
{
92
0
    interpolationobject *self = interpolationobject_CAST(op);
93
0
    Py_CLEAR(self->value);
94
0
    Py_CLEAR(self->expression);
95
0
    Py_CLEAR(self->conversion);
96
0
    Py_CLEAR(self->format_spec);
97
0
    return 0;
98
0
}
99
100
static int
101
interpolation_traverse(PyObject *op, visitproc visit, void *arg)
102
0
{
103
0
    interpolationobject *self = interpolationobject_CAST(op);
104
0
    Py_VISIT(self->value);
105
0
    Py_VISIT(self->expression);
106
0
    Py_VISIT(self->conversion);
107
0
    Py_VISIT(self->format_spec);
108
0
    return 0;
109
0
}
110
111
static PyObject *
112
interpolation_repr(PyObject *op)
113
0
{
114
0
    interpolationobject *self = interpolationobject_CAST(op);
115
0
    return PyUnicode_FromFormat("%s(%R, %R, %R, %R)",
116
0
                                _PyType_Name(Py_TYPE(self)), self->value, self->expression,
117
0
                                self->conversion, self->format_spec);
118
0
}
119
120
static PyMemberDef interpolation_members[] = {
121
    {"value", Py_T_OBJECT_EX, offsetof(interpolationobject, value), Py_READONLY, "Value"},
122
    {"expression", Py_T_OBJECT_EX, offsetof(interpolationobject, expression), Py_READONLY, "Expression"},
123
    {"conversion", Py_T_OBJECT_EX, offsetof(interpolationobject, conversion), Py_READONLY, "Conversion"},
124
    {"format_spec", Py_T_OBJECT_EX, offsetof(interpolationobject, format_spec), Py_READONLY, "Format specifier"},
125
    {NULL}
126
};
127
128
static PyObject*
129
interpolation_reduce(PyObject *op, PyObject *Py_UNUSED(dummy))
130
0
{
131
0
    interpolationobject *self = interpolationobject_CAST(op);
132
0
    return Py_BuildValue("(O(OOOO))", (PyObject *)Py_TYPE(op),
133
0
                         self->value, self->expression,
134
0
                         self->conversion, self->format_spec);
135
0
}
136
137
static PyMethodDef interpolation_methods[] = {
138
    {"__reduce__", interpolation_reduce, METH_NOARGS,
139
        PyDoc_STR("__reduce__() -> (cls, state)")},
140
    {"__class_getitem__", Py_GenericAlias,
141
        METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
142
    {NULL, NULL},
143
};
144
145
PyTypeObject _PyInterpolation_Type = {
146
    PyVarObject_HEAD_INIT(NULL, 0)
147
    .tp_name = "string.templatelib.Interpolation",
148
    .tp_doc = PyDoc_STR("Interpolation object"),
149
    .tp_basicsize = sizeof(interpolationobject),
150
    .tp_itemsize = 0,
151
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
152
    .tp_new = interpolation_new,
153
    .tp_alloc = PyType_GenericAlloc,
154
    .tp_dealloc = interpolation_dealloc,
155
    .tp_clear = interpolation_clear,
156
    .tp_free = PyObject_GC_Del,
157
    .tp_repr = interpolation_repr,
158
    .tp_members = interpolation_members,
159
    .tp_methods = interpolation_methods,
160
    .tp_traverse = interpolation_traverse,
161
};
162
163
PyStatus
164
_PyInterpolation_InitTypes(PyInterpreterState *interp)
165
16
{
166
16
    PyObject *tuple = Py_BuildValue("(ssss)", "value", "expression", "conversion", "format_spec");
167
16
    if (!tuple) {
168
0
        goto error;
169
0
    }
170
171
16
    PyObject *dict = _PyType_GetDict(&_PyInterpolation_Type);
172
16
    if (!dict) {
173
0
        Py_DECREF(tuple);
174
0
        goto error;
175
0
    }
176
177
16
    int status = PyDict_SetItemString(dict, "__match_args__", tuple);
178
16
    Py_DECREF(tuple);
179
16
    if (status < 0) {
180
0
        goto error;
181
0
    }
182
16
    return _PyStatus_OK();
183
184
0
error:
185
0
    return _PyStatus_ERR("Can't initialize interpolation types");
186
16
}
187
188
PyObject *
189
_PyInterpolation_Build(PyObject *value, PyObject *str, int conversion, PyObject *format_spec)
190
0
{
191
0
    interpolationobject *interpolation = PyObject_GC_New(interpolationobject, &_PyInterpolation_Type);
192
0
    if (!interpolation) {
193
0
        return NULL;
194
0
    }
195
196
0
    interpolation->value = Py_NewRef(value);
197
0
    interpolation->expression = Py_NewRef(str);
198
0
    interpolation->format_spec = Py_NewRef(format_spec);
199
0
    interpolation->conversion = NULL;
200
201
0
    if (conversion == 0) {
202
0
        interpolation->conversion = Py_None;
203
0
    }
204
0
    else {
205
0
        switch (conversion) {
206
0
            case FVC_ASCII:
207
0
                interpolation->conversion = _Py_LATIN1_CHR('a');
208
0
                break;
209
0
            case FVC_REPR:
210
0
                interpolation->conversion = _Py_LATIN1_CHR('r');
211
0
                break;
212
0
            case FVC_STR:
213
0
                interpolation->conversion = _Py_LATIN1_CHR('s');
214
0
                break;
215
0
            default:
216
0
                PyErr_SetString(PyExc_SystemError,
217
0
                    "Interpolation() argument 'conversion' must be one of 's', 'a' or 'r'");
218
0
                Py_DECREF(interpolation);
219
0
                return NULL;
220
0
        }
221
0
    }
222
223
0
    PyObject_GC_Track(interpolation);
224
0
    return (PyObject *) interpolation;
225
0
}
226
227
PyObject *
228
_PyInterpolation_GetValueRef(PyObject *interpolation)
229
0
{
230
0
    return Py_NewRef(interpolationobject_CAST(interpolation)->value);
231
0
}