• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

llnl / dftracer-utils / 28286012595

27 Jun 2026 10:04AM UTC coverage: 51.056% (-1.3%) from 52.356%
28286012595

Pull #79

github

web-flow
Merge 6c6535a19 into 8eb383f39
Pull Request #79: Add Valgrind memory checking (C++, Python, MPI) and fix the bugs it found

32079 of 80165 branches covered (40.02%)

Branch coverage included in aggregate %.

129 of 149 new or added lines in 11 files covered. (86.58%)

5116 existing lines in 181 files now uncovered.

32739 of 46790 relevant lines covered (69.97%)

9929.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.79
/src/dftracer/utils/python/indexer.cpp
1
#include <dftracer/utils/core/runtime.h>
2
#include <dftracer/utils/core/tasks/coro_scope.h>
3
#include <dftracer/utils/python/indexer.h>
4
#include <dftracer/utils/python/indexer_checkpoint.h>
5
#include <dftracer/utils/python/runtime.h>
6
#include <dftracer/utils/utilities/composites/dft/internal/utils.h>
7
#include <dftracer/utils/utilities/indexer/index_builder_utility.h>
8
#include <dftracer/utils/utilities/indexer/index_database.h>
9
#include <dftracer/utils/utilities/indexer/internal/helpers.h>
10
#include <structmember.h>
11

12
#include <cstring>
13
#include <memory>
14

15
static void CheckpointIndexer_dealloc(CheckpointIndexerObject *self) {
71✔
16
    if (self->handle) {
71✔
17
        // The Python wrapper owns only the native indexer handle. The
18
        // underlying RocksDB instance remains manager-owned and may continue to
19
        // live process-wide for the same .dftindex path.
20
        dft_indexer_destroy(self->handle);
6✔
21
        self->handle = NULL;
6✔
22
    }
6✔
23
    Py_XDECREF(self->gz_path);
71✔
24
    Py_XDECREF(self->index_path);
71✔
25
    Py_XDECREF(self->runtime_obj);
71✔
26
    Py_TYPE(self)->tp_free((PyObject *)self);
71✔
27
}
71✔
28

29
static void CheckpointIndexer_release_handle(CheckpointIndexerObject *self) {
64✔
30
    if (self->handle) {
64!
31
        // Releasing the handle drops this wrapper's native indexer state only.
32
        // Shared RocksDB lifetime is managed separately by RocksDBManager.
33
        dft_indexer_destroy(self->handle);
64✔
34
        self->handle = NULL;
64✔
35
    }
64✔
36
}
64✔
37

38
static PyObject *CheckpointIndexer_new(PyTypeObject *type, PyObject *args,
65✔
39
                                       PyObject *kwds) {
40
    CheckpointIndexerObject *self;
41
    self = (CheckpointIndexerObject *)type->tp_alloc(type, 0);
65✔
42
    if (self != NULL) {
65!
43
        self->handle = NULL;
65✔
44
        self->gz_path = NULL;
65✔
45
        self->index_path = NULL;
65✔
46
        self->checkpoint_size = 0;
65✔
47
        self->build_bloom = 0;
65✔
48
        self->build_manifest = 0;
65✔
49
        self->runtime_obj = NULL;
65✔
50
    }
65✔
51
    return (PyObject *)self;
65✔
52
}
53

54
static int CheckpointIndexer_init(CheckpointIndexerObject *self, PyObject *args,
65✔
55
                                  PyObject *kwds) {
56
    static const char *kwlist[] = {
57
        "gz_path",     "index_path",     "checkpoint_size", "force_rebuild",
58
        "build_bloom", "build_manifest", "runtime",         NULL};
59
    const char *gz_path;
60
    const char *index_path = NULL;
65✔
61
    std::uint64_t checkpoint_size =
65✔
62
        dftracer::utils::constants::indexer::DEFAULT_CHECKPOINT_SIZE;
63
    int force_rebuild = 0;
65✔
64
    int build_bloom = 0;
65✔
65
    int build_manifest = 0;
65✔
66
    PyObject *runtime_arg = NULL;
65✔
67

68
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|snpppO", (char **)kwlist,
65!
69
                                     &gz_path, &index_path, &checkpoint_size,
70
                                     &force_rebuild, &build_bloom,
71
                                     &build_manifest, &runtime_arg)) {
72
        return -1;
×
73
    }
74

75
    if (runtime_arg && runtime_arg != Py_None) {
65!
76
        if (PyObject_TypeCheck(runtime_arg, &RuntimeType)) {
×
77
            Py_INCREF(runtime_arg);
×
78
            self->runtime_obj = runtime_arg;
×
UNCOV
79
        } else {
×
80
            PyObject *native = PyObject_GetAttrString(runtime_arg, "_native");
×
81
            if (native && PyObject_TypeCheck(native, &RuntimeType)) {
×
82
                self->runtime_obj = native;
×
UNCOV
83
            } else {
×
84
                Py_XDECREF(native);
×
85
                PyErr_SetString(PyExc_TypeError,
×
86
                                "runtime must be a Runtime instance or None");
87
                return -1;
×
88
            }
89
        }
UNCOV
90
    }
×
91

92
    self->gz_path = PyUnicode_FromString(gz_path);
65✔
93
    if (!self->gz_path) {
65!
94
        return -1;
×
95
    }
96

97
    if (index_path) {
65✔
98
        self->index_path = PyUnicode_FromString(index_path);
64✔
99
    } else {
64✔
100
        const std::string index_path = dftracer::utils::utilities::composites::
1!
101
            dft::internal::determine_index_path(gz_path, "");
1!
102
        self->index_path = PyUnicode_FromString(index_path.c_str());
1!
103
    }
1✔
104

105
    if (!self->index_path) {
65!
106
        Py_DECREF(self->gz_path);
×
107
        return -1;
×
108
    }
109

110
    self->checkpoint_size = checkpoint_size;
65✔
111
    self->build_bloom = build_bloom;
65✔
112
    self->build_manifest = build_manifest;
65✔
113

114
    const char *index_path_str = PyUnicode_AsUTF8(self->index_path);
65✔
115
    if (!index_path_str) {
65!
116
        return -1;
×
117
    }
118

119
    self->handle = dft_indexer_create(gz_path, index_path_str, checkpoint_size,
130✔
120
                                      force_rebuild);
65✔
121
    if (!self->handle) {
65✔
122
        PyErr_SetString(PyExc_RuntimeError, "Failed to create indexer");
1✔
123
        return -1;
1✔
124
    }
125

126
    return 0;
64✔
127
}
65✔
128

129
static dftracer::utils::Runtime *get_indexer_runtime(
16✔
130
    CheckpointIndexerObject *self) {
131
    if (self->runtime_obj) {
16!
132
        return ((RuntimeObject *)self->runtime_obj)->runtime.get();
×
133
    }
134
    return get_default_runtime();
16✔
135
}
16✔
136

137
static PyObject *CheckpointIndexer_build(CheckpointIndexerObject *self,
62✔
138
                                         PyObject *Py_UNUSED(ignored)) {
139
    if (!self->handle) {
62!
140
        PyErr_SetString(PyExc_RuntimeError, "Indexer not initialized");
×
141
        return NULL;
×
142
    }
143

144
    // Use IndexBatchBuilderUtility when bloom or manifest is requested.
145
    // Otherwise, use the simpler dft_indexer_build which only creates
146
    // checkpoints.
147
    if (self->build_bloom || self->build_manifest) {
62✔
148
        using namespace dftracer::utils;
149
        using namespace dftracer::utils::utilities::indexer;
150

151
        const char *gz = PyUnicode_AsUTF8(self->gz_path);
16✔
152
        const char *idx = PyUnicode_AsUTF8(self->index_path);
16✔
153
        if (!gz || !idx) {
16!
154
            return NULL;
×
155
        }
156

157
        auto batch_config = std::make_shared<IndexBuildBatchConfig>();
16✔
158
        batch_config->file_paths.emplace_back(gz);
16!
159
        batch_config->checkpoint_size =
16✔
160
            static_cast<std::size_t>(self->checkpoint_size);
16✔
161
        batch_config->build_manifest = self->build_manifest != 0;
16✔
162
        batch_config->parallelism = 1;
16✔
163
        batch_config->use_batch_write = true;
16✔
164
        batch_config->rebuild_root_summaries = true;
16✔
165

166
        std::string idx_str(idx);
16!
167
        auto pos = idx_str.find_last_of('/');
16✔
168
        if (pos != std::string::npos) {
16!
169
            batch_config->index_dir = idx_str.substr(0, pos);
16!
170
        }
16✔
171

172
        Runtime *rt = get_indexer_runtime(self);
16!
173
        IndexBuildBatchResult batch_result;
16✔
174

175
        try {
176
            Py_BEGIN_ALLOW_THREADS rt
32!
177
                ->submit(
16!
178
                    run_coro_scope(
16!
179
                        rt->executor(),
16!
180
                        [](CoroScope &scope,
112!
181
                           std::shared_ptr<IndexBuildBatchConfig> cfg,
182
                           IndexBuildBatchResult *out) -> coro::CoroTask<void> {
16!
183
                            *out = co_await IndexBatchBuilderUtility::process(
128!
184
                                &scope, std::move(cfg));
48✔
185
                        },
32✔
186
                        batch_config, &batch_result),
16✔
187
                    "indexer-build")
16!
188
                .get();
16!
189
            Py_END_ALLOW_THREADS
16!
190
        } catch (const std::exception &e) {
16!
191
            PyErr_SetString(PyExc_RuntimeError, e.what());
×
192
            return NULL;
×
193
        }
×
194

195
        if (batch_result.failed > 0 && !batch_result.results.empty()) {
16!
196
            const auto &result = batch_result.results[0];
×
197
            if (!result.success) {
×
198
                PyErr_SetString(PyExc_RuntimeError,
×
UNCOV
199
                                result.error_message.c_str());
×
200
                return NULL;
×
201
            }
UNCOV
202
        }
×
203
    } else {
16!
204
        // Simple checkpoint-only build
205
        int result;
206
        Py_BEGIN_ALLOW_THREADS result = dft_indexer_build(self->handle);
46✔
207
        Py_END_ALLOW_THREADS
46✔
208

209
            if (result < 0) {
46!
210
            PyErr_SetString(PyExc_RuntimeError, "Failed to build index");
×
211
            return NULL;
×
212
        }
213
    }
214

215
    Py_RETURN_NONE;
62✔
216
}
62✔
217

218
static PyObject *CheckpointIndexer_need_rebuild(CheckpointIndexerObject *self,
30✔
219
                                                PyObject *Py_UNUSED(ignored)) {
220
    if (!self->handle) {
30!
221
        PyErr_SetString(PyExc_RuntimeError, "Indexer not initialized");
×
222
        return NULL;
×
223
    }
224

225
    int result = dft_indexer_need_rebuild(self->handle);
30✔
226
    return PyBool_FromLong(result);
30✔
227
}
30✔
228

229
static PyObject *CheckpointIndexer_exists(CheckpointIndexerObject *self,
×
230
                                          PyObject *Py_UNUSED(ignored)) {
231
    if (!self->handle) {
×
232
        PyErr_SetString(PyExc_RuntimeError, "Indexer not initialized");
×
233
        return NULL;
×
234
    }
235

236
    int result = dft_indexer_exists(self->handle);
×
237
    return PyBool_FromLong(result);
×
UNCOV
238
}
×
239

240
static PyObject *CheckpointIndexer_get_max_bytes(CheckpointIndexerObject *self,
4✔
241
                                                 PyObject *Py_UNUSED(ignored)) {
242
    if (!self->handle) {
4!
243
        PyErr_SetString(PyExc_RuntimeError, "Indexer not initialized");
×
244
        return NULL;
×
245
    }
246

247
    uint64_t result = dft_indexer_get_max_bytes(self->handle);
4✔
248
    return PyLong_FromUnsignedLongLong(result);
4✔
249
}
4✔
250

251
static PyObject *CheckpointIndexer_get_num_lines(CheckpointIndexerObject *self,
5✔
252
                                                 PyObject *Py_UNUSED(ignored)) {
253
    if (!self->handle) {
5!
254
        PyErr_SetString(PyExc_RuntimeError, "Indexer not initialized");
×
255
        return NULL;
×
256
    }
257

258
    uint64_t result = dft_indexer_get_num_lines(self->handle);
5✔
259
    return PyLong_FromUnsignedLongLong(result);
5✔
260
}
5✔
261

262
static PyObject *CheckpointIndexer_find_checkpoint(
3✔
263
    CheckpointIndexerObject *self, PyObject *args) {
264
    if (!self->handle) {
3!
265
        PyErr_SetString(PyExc_RuntimeError, "Indexer not initialized");
×
266
        return NULL;
×
267
    }
268

269
    std::size_t target_offset;
270
    if (!PyArg_ParseTuple(args, "n", &target_offset)) {
3!
271
        return NULL;
×
272
    }
273

274
    dft_indexer_checkpoint_t checkpoint;
275
    int found =
3✔
276
        dft_indexer_find_checkpoint(self->handle, target_offset, &checkpoint);
3✔
277

278
    if (!found) {
3✔
279
        Py_RETURN_NONE;
1✔
280
    }
281

282
    // Create IndexerCheckpoint object
283
    IndexerCheckpointObject *cp_obj =
2✔
284
        (IndexerCheckpointObject *)IndexerCheckpoint_new(&IndexerCheckpointType,
2✔
285
                                                         NULL, NULL);
286
    if (!cp_obj) {
2!
287
        return NULL;
×
288
    }
289

290
    cp_obj->checkpoint = checkpoint;
2✔
291
    return (PyObject *)cp_obj;
2✔
292
}
3✔
293

294
static PyObject *CheckpointIndexer_get_checkpoints(
3✔
295
    CheckpointIndexerObject *self, PyObject *Py_UNUSED(ignored)) {
296
    if (!self->handle) {
3!
297
        PyErr_SetString(PyExc_RuntimeError, "Indexer not initialized");
×
298
        return NULL;
×
299
    }
300

301
    dft_indexer_checkpoint_t *checkpoints = NULL;
3✔
302
    std::size_t count = 0;
3✔
303

304
    int result =
3✔
305
        dft_indexer_get_checkpoints(self->handle, &checkpoints, &count);
3✔
306
    if (result != 0 || !checkpoints) {
3!
307
        dft_indexer_free_checkpoints(checkpoints, count);
1✔
308
        PyObject *list = PyList_New(0);
1✔
309
        return list;
1✔
310
    }
311

312
    PyObject *list = PyList_New(count);
2✔
313
    if (!list) {
2!
314
        dft_indexer_free_checkpoints(checkpoints, count);
×
315
        return NULL;
×
316
    }
317

318
    for (std::size_t i = 0; i < count; i++) {
85✔
319
        IndexerCheckpointObject *cp_obj =
83✔
320
            (IndexerCheckpointObject *)IndexerCheckpoint_new(
83✔
321
                &IndexerCheckpointType, NULL, NULL);
322
        if (!cp_obj) {
83!
UNCOV
323
            Py_DECREF(list);
×
324
            dft_indexer_free_checkpoints(checkpoints, count);
×
325
            return NULL;
×
326
        }
327
        cp_obj->checkpoint = checkpoints[i];
83✔
328
        checkpoints[i].dict_compressed = NULL;
83✔
329
        PyList_SetItem(list, i, (PyObject *)cp_obj);
83✔
330
    }
83✔
331

332
    dft_indexer_free_checkpoints(checkpoints, count);
2✔
333
    return list;
2✔
334
}
3✔
335

336
static PyObject *CheckpointIndexer_has_bloom(CheckpointIndexerObject *self,
6✔
337
                                             void *closure) {
338
    const char *idx = PyUnicode_AsUTF8(self->index_path);
6✔
339
    const char *gz = PyUnicode_AsUTF8(self->gz_path);
6✔
340
    if (!idx || !gz) {
6!
341
        Py_RETURN_FALSE;
×
342
    }
343
    try {
344
        using namespace dftracer::utils::utilities::indexer;
345
        using namespace dftracer::utils::utilities::indexer::internal;
346
        IndexDatabase db(
6!
347
            idx, dftracer::utils::rocksdb::RocksDatabase::OpenMode::ReadOnly);
6!
348
        std::string logical = get_logical_path(gz);
6!
349
        int fid = db.get_file_info_id(logical);
6!
350
        if (fid >= 0 && db.has_bloom_data(fid)) {
6!
351
            Py_RETURN_TRUE;
1✔
352
        }
353
    } catch (...) {
6!
354
    }
×
355
    Py_RETURN_FALSE;
5✔
356
}
6✔
357

358
static PyObject *CheckpointIndexer_has_manifest(CheckpointIndexerObject *self,
3✔
359
                                                void *closure) {
360
    const char *idx = PyUnicode_AsUTF8(self->index_path);
3✔
361
    const char *gz = PyUnicode_AsUTF8(self->gz_path);
3✔
362
    if (!idx || !gz) {
3!
363
        Py_RETURN_FALSE;
×
364
    }
365
    try {
366
        using namespace dftracer::utils::utilities::indexer;
367
        using namespace dftracer::utils::utilities::indexer::internal;
368
        IndexDatabase db(
3!
369
            idx, dftracer::utils::rocksdb::RocksDatabase::OpenMode::ReadOnly);
3!
370
        std::string logical = get_logical_path(gz);
3!
371
        int fid = db.get_file_info_id(logical);
3!
372
        if (fid >= 0 && db.has_manifest_data(fid)) {
3!
373
            Py_RETURN_TRUE;
1✔
374
        }
375
    } catch (...) {
3!
376
    }
×
377
    Py_RETURN_FALSE;
2✔
378
}
3✔
379

380
static PyObject *CheckpointIndexer_gz_path(CheckpointIndexerObject *self,
3✔
381
                                           void *closure) {
382
    Py_INCREF(self->gz_path);
3✔
383
    return self->gz_path;
3✔
384
}
385

386
static PyObject *CheckpointIndexer_index_path(CheckpointIndexerObject *self,
2✔
387
                                              void *closure) {
388
    Py_INCREF(self->index_path);
2✔
389
    return self->index_path;
2✔
390
}
391

392
static PyObject *CheckpointIndexer_checkpoint_size(
2✔
393
    CheckpointIndexerObject *self, void *closure) {
394
    return PyLong_FromUnsignedLongLong(self->checkpoint_size);
2✔
395
}
396

397
static PyObject *CheckpointIndexer_enter(CheckpointIndexerObject *self,
63✔
398
                                         PyObject *Py_UNUSED(ignored)) {
399
    Py_INCREF(self);
63✔
400
    return (PyObject *)self;
63✔
401
}
402

403
static PyObject *CheckpointIndexer_close(CheckpointIndexerObject *self,
1✔
404
                                         PyObject *Py_UNUSED(ignored)) {
405
    CheckpointIndexer_release_handle(self);
1✔
406
    Py_RETURN_NONE;
1✔
407
}
408

409
static PyObject *CheckpointIndexer_exit(CheckpointIndexerObject *self,
63✔
410
                                        PyObject *args) {
411
    CheckpointIndexer_release_handle(self);
63✔
412
    Py_RETURN_NONE;
63✔
413
}
414

415
static PyMethodDef CheckpointIndexer_methods[] = {
416
    {"build", (PyCFunction)CheckpointIndexer_build, METH_NOARGS,
417
     "build()\n"
418
     "--\n"
419
     "\n"
420
     "Build or rebuild the index.\n"},
421
    {"need_rebuild", (PyCFunction)CheckpointIndexer_need_rebuild, METH_NOARGS,
422
     "Check if a rebuild is needed."},
423
    {"exists", (PyCFunction)CheckpointIndexer_exists, METH_NOARGS,
424
     "Check if the .dftindex store exists."},
425
    {"get_max_bytes", (PyCFunction)CheckpointIndexer_get_max_bytes, METH_NOARGS,
426
     "Get the maximum uncompressed bytes in the indexed file."},
427
    {"get_num_lines", (PyCFunction)CheckpointIndexer_get_num_lines, METH_NOARGS,
428
     "Get the total number of lines in the indexed file."},
429
    {"find_checkpoint", (PyCFunction)CheckpointIndexer_find_checkpoint,
430
     METH_VARARGS,
431
     "Find the best checkpoint for a given uncompressed offset.\n"
432
     "\n"
433
     "Args:\n"
434
     "    offset (int): Uncompressed byte offset.\n"},
435
    {"get_checkpoints", (PyCFunction)CheckpointIndexer_get_checkpoints,
436
     METH_NOARGS, "Get all checkpoints for this file as a list."},
437
    {"close", (PyCFunction)CheckpointIndexer_close, METH_NOARGS,
438
     "Release this Python wrapper's native indexer handle.\n"
439
     "\n"
440
     "The shared RocksDB instance for the same .dftindex path remains managed\n"
441
     "by the native RocksDBManager cache."},
442
    {"__enter__", (PyCFunction)CheckpointIndexer_enter, METH_NOARGS,
443
     "Enter the runtime context for the with statement."},
444
    {"__exit__", (PyCFunction)CheckpointIndexer_exit, METH_VARARGS,
445
     "Release this Python wrapper on context exit.\n"
446
     "\n"
447
     "This does not force-close the shared RocksDB instance for the same\n"
448
     ".dftindex path."},
449
    {NULL} /* Sentinel */
450
};
451

452
static PyGetSetDef CheckpointIndexer_getsetters[] = {
453
    {"gz_path", (getter)CheckpointIndexer_gz_path, NULL,
454
     "Path to the gzip file", NULL},
455
    {"index_path", (getter)CheckpointIndexer_index_path, NULL,
456
     "Path to the .dftindex store", NULL},
457
    {"checkpoint_size", (getter)CheckpointIndexer_checkpoint_size, NULL,
458
     "Checkpoint size in bytes", NULL},
459
    {"has_bloom", (getter)CheckpointIndexer_has_bloom, NULL,
460
     "Whether bloom data exists in index", NULL},
461
    {"has_manifest", (getter)CheckpointIndexer_has_manifest, NULL,
462
     "Whether manifest data exists in index", NULL},
463
    {NULL} /* Sentinel */
464
};
465

466
PyTypeObject CheckpointIndexerType = {
467
    PyVarObject_HEAD_INIT(
468
        NULL, 0) "dftracer_utils_ext.CheckpointIndexer", /* tp_name */
469
    sizeof(CheckpointIndexerObject),                     /* tp_basicsize */
470
    0,                                                   /* tp_itemsize */
471
    (destructor)CheckpointIndexer_dealloc,               /* tp_dealloc */
472
    0,                                        /* tp_vectorcall_offset */
473
    0,                                        /* tp_getattr */
474
    0,                                        /* tp_setattr */
475
    0,                                        /* tp_as_async */
476
    0,                                        /* tp_repr */
477
    0,                                        /* tp_as_number */
478
    0,                                        /* tp_as_sequence */
479
    0,                                        /* tp_as_mapping */
480
    0,                                        /* tp_hash */
481
    0,                                        /* tp_call */
482
    0,                                        /* tp_str */
483
    0,                                        /* tp_getattro */
484
    0,                                        /* tp_setattro */
485
    0,                                        /* tp_as_buffer */
486
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
487
    "CheckpointIndexer(gz_path, index_path=None, checkpoint_size=1048576, "
488
    "force_rebuild=False, build_bloom=False, build_manifest=False, "
489
    "runtime=None)\n"
490
    "--\n"
491
    "\n"
492
    "Checkpoint indexer for single-file checkpoint-level operations on a "
493
    "gzip trace.\n"
494
    "\n"
495
    "Args:\n"
496
    "    gz_path (str): Path to the gzip trace file.\n"
497
    "    index_path (str or None): Path to the .dftindex store. If None,\n"
498
    "        uses the root-local \".dftindex\" next to gz_path.\n"
499
    "    checkpoint_size (int): Checkpoint size in bytes for index\n"
500
    "        building (default 1 MB).\n"
501
    "    force_rebuild (bool): If True, rebuild the index even if it\n"
502
    "        exists.\n"
503
    "    build_bloom (bool): If True, build bloom filter data in the\n"
504
    "        index.\n"
505
    "    build_manifest (bool): If True, build manifest data in the\n"
506
    "        store.\n"
507
    "    runtime (Runtime or None): Runtime instance for thread pool\n"
508
    "        control. If None, uses the default global Runtime.\n", /* tp_doc */
509
    0,                                /* tp_traverse */
510
    0,                                /* tp_clear */
511
    0,                                /* tp_richcompare */
512
    0,                                /* tp_weaklistoffset */
513
    0,                                /* tp_iter */
514
    0,                                /* tp_iternext */
515
    CheckpointIndexer_methods,        /* tp_methods */
516
    0,                                /* tp_members */
517
    CheckpointIndexer_getsetters,     /* tp_getset */
518
    0,                                /* tp_base */
519
    0,                                /* tp_dict */
520
    0,                                /* tp_descr_get */
521
    0,                                /* tp_descr_set */
522
    0,                                /* tp_dictoffset */
523
    (initproc)CheckpointIndexer_init, /* tp_init */
524
    0,                                /* tp_alloc */
525
    CheckpointIndexer_new,            /* tp_new */
526
};
527

528
int init_checkpoint_indexer(PyObject *m) {
1✔
529
    if (PyType_Ready(&CheckpointIndexerType) < 0) return -1;
1!
530

531
    Py_INCREF(&CheckpointIndexerType);
1✔
532
    if (PyModule_AddObject(m, "CheckpointIndexer",
2!
533
                           (PyObject *)&CheckpointIndexerType) < 0) {
1✔
UNCOV
534
        Py_DECREF(&CheckpointIndexerType);
×
UNCOV
535
        Py_DECREF(m);
×
536
        return -1;
×
537
    }
538

539
    return 0;
1✔
540
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc