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

llnl / dftracer-utils / 28521653886

01 Jul 2026 01:36PM UTC coverage: 50.92% (-1.4%) from 52.278%
28521653886

Pull #83

github

web-flow
Merge 9bdedb1e9 into 2efed6649
Pull Request #83: refactor and improve code QoL

31893 of 80049 branches covered (39.84%)

Branch coverage included in aggregate %.

789 of 1613 new or added lines in 87 files covered. (48.92%)

5007 existing lines in 181 files now uncovered.

32812 of 47024 relevant lines covered (69.78%)

9905.42 hits per line

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

2.7
/src/dftracer/utils/python/task_handle.cpp
1
#define PY_SSIZE_T_CLEAN
2
#include <Python.h>
3
#include <dftracer/utils/python/py_errors.h>
4
#include <dftracer/utils/python/py_type_helpers.h>
5
#include <dftracer/utils/python/task_handle.h>
6

7
#include <any>
8
#include <chrono>
9
#include <future>
10
#include <string>
11

12
static void TaskHandle_dealloc(TaskHandleObject *self) {
×
13
    self->future.~shared_future();
×
14
    self->typed_future.~shared_future();
×
15
    self->name.~basic_string();
×
16
    Py_TYPE(self)->tp_free((PyObject *)self);
×
17
}
×
18

19
static PyObject *TaskHandle_new(PyTypeObject *type, PyObject * /*args*/,
×
20
                                PyObject * /*kwds*/) {
21
    TaskHandleObject *self = (TaskHandleObject *)type->tp_alloc(type, 0);
×
22
    if (self) {
×
23
        new (&self->future) std::shared_future<void>();
×
24
        new (&self->typed_future) std::shared_future<std::any>();
×
25
        new (&self->name) std::string();
×
26
        self->has_typed_future = false;
×
27
        self->task_id = -1;
×
UNCOV
28
    }
×
29
    return (PyObject *)self;
×
30
}
31

32
static PyObject *TaskHandle_get(TaskHandleObject *self,
×
33
                                PyObject *Py_UNUSED(ignored)) {
34
    if (!self->future.valid()) {
×
35
        Py_RETURN_NONE;
×
36
    }
37
    if (self->has_typed_future) {
×
38
        std::any result;
×
39
        try {
40
            Py_BEGIN_ALLOW_THREADS result = self->typed_future.get();
×
41
            Py_END_ALLOW_THREADS
×
42
        } catch (const std::exception &e) {
×
NEW
43
            set_typed_py_error(e);
×
44
            return NULL;
×
45
        } catch (...) {
×
46
            PyErr_SetString(PyExc_RuntimeError, "Unknown error in task");
×
47
            return NULL;
×
48
        }
×
49
        if (result.has_value()) {
×
50
            try {
51
                PyObject *obj = std::any_cast<PyObject *>(result);
×
52
                if (obj) {
×
UNCOV
53
                    Py_INCREF(obj);
×
54
                    return obj;
×
55
                }
56
            } catch (const std::bad_any_cast &) {
×
57
                // Not a PyObject* — fall through to None
58
            }
×
UNCOV
59
        }
×
60
        Py_RETURN_NONE;
×
61
    }
×
62

63
    // Void task: .get() returns void and rethrows stored exceptions.
64
    try {
65
        Py_BEGIN_ALLOW_THREADS self->future.get();
×
66
        Py_END_ALLOW_THREADS
×
67
    } catch (const std::exception &e) {
×
NEW
68
        set_typed_py_error(e);
×
69
        return NULL;
×
70
    } catch (...) {
×
71
        PyErr_SetString(PyExc_RuntimeError, "Unknown error in task");
×
72
        return NULL;
×
73
    }
×
74
    Py_RETURN_NONE;
×
UNCOV
75
}
×
76

77
static PyObject *TaskHandle_wait(TaskHandleObject *self,
×
78
                                 PyObject *Py_UNUSED(ignored)) {
79
    if (!self->future.valid()) {
×
80
        Py_RETURN_NONE;
×
81
    }
82
    // Use .get() (not .wait()) so stored exceptions are rethrown.
83
    try {
84
        Py_BEGIN_ALLOW_THREADS self->future.get();
×
85
        Py_END_ALLOW_THREADS
×
86
    } catch (const std::exception &e) {
×
NEW
87
        set_typed_py_error(e);
×
88
        return NULL;
×
89
    } catch (...) {
×
90
        PyErr_SetString(PyExc_RuntimeError, "Unknown error in task");
×
91
        return NULL;
×
92
    }
×
93
    Py_RETURN_NONE;
×
UNCOV
94
}
×
95

96
static PyObject *TaskHandle_done(TaskHandleObject *self,
×
97
                                 PyObject *Py_UNUSED(ignored)) {
98
    if (!self->future.valid()) {
×
99
        Py_RETURN_FALSE;
×
100
    }
101
    bool is_done = self->future.wait_for(std::chrono::seconds(0)) ==
×
102
                   std::future_status::ready;
103
    return PyBool_FromLong(is_done ? 1 : 0);
×
UNCOV
104
}
×
105

106
static PyObject *TaskHandle_get_name(TaskHandleObject *self, void *) {
×
107
    return PyUnicode_FromStringAndSize(
×
108
        self->name.data(), static_cast<Py_ssize_t>(self->name.size()));
×
109
}
110

111
static PyObject *TaskHandle_get_task_id(TaskHandleObject *self, void *) {
×
112
    return PyLong_FromLongLong(static_cast<long long>(self->task_id));
×
113
}
114

115
static PyMethodDef TaskHandle_methods[] = {
116
    {"get", (PyCFunction)TaskHandle_get, METH_NOARGS,
117
     "Block until task completes and return result.\n"
118
     "Raises RuntimeError if the task failed."},
119
    {"wait", (PyCFunction)TaskHandle_wait, METH_NOARGS,
120
     "Block until task completes.\n"
121
     "Raises RuntimeError if the task failed."},
122
    {"done", (PyCFunction)TaskHandle_done, METH_NOARGS,
123
     "Return True if task has completed."},
124
    {NULL}};
125

126
static PyGetSetDef TaskHandle_getsetters[] = {
127
    {"name", (getter)TaskHandle_get_name, NULL, "Task name", NULL},
128
    {"task_id", (getter)TaskHandle_get_task_id, NULL, "Task identifier", NULL},
129
    {NULL}};
130

131
PyTypeObject TaskHandleType = {
132
    PyVarObject_HEAD_INIT(NULL, 0) "dftracer_utils_ext.TaskHandle",
133
    sizeof(TaskHandleObject),                       /* tp_basicsize */
134
    0,                                              /* tp_itemsize */
135
    (destructor)TaskHandle_dealloc,                 /* tp_dealloc */
136
    0,                                              /* tp_vectorcall_offset */
137
    0,                                              /* tp_getattr */
138
    0,                                              /* tp_setattr */
139
    0,                                              /* tp_as_async */
140
    0,                                              /* tp_repr */
141
    0,                                              /* tp_as_number */
142
    0,                                              /* tp_as_sequence */
143
    0,                                              /* tp_as_mapping */
144
    0,                                              /* tp_hash */
145
    0,                                              /* tp_call */
146
    0,                                              /* tp_str */
147
    0,                                              /* tp_getattro */
148
    0,                                              /* tp_setattro */
149
    0,                                              /* tp_as_buffer */
150
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,       /* tp_flags */
151
    "Handle to an async task submitted to Runtime", /* tp_doc */
152
    0,                                              /* tp_traverse */
153
    0,                                              /* tp_clear */
154
    0,                                              /* tp_richcompare */
155
    0,                                              /* tp_weaklistoffset */
156
    0,                                              /* tp_iter */
157
    0,                                              /* tp_iternext */
158
    TaskHandle_methods,                             /* tp_methods */
159
    0,                                              /* tp_members */
160
    TaskHandle_getsetters,                          /* tp_getset */
161
    0,                                              /* tp_base */
162
    0,                                              /* tp_dict */
163
    0,                                              /* tp_descr_get */
164
    0,                                              /* tp_descr_set */
165
    0,                                              /* tp_dictoffset */
166
    0,                                              /* tp_init */
167
    0,                                              /* tp_alloc */
168
    TaskHandle_new,                                 /* tp_new */
169
};
170

171
PyObject *create_task_handle(dftracer::utils::TaskHandle handle) {
×
UNCOV
172
    TaskHandleObject *obj =
×
173
        (TaskHandleObject *)TaskHandleType.tp_alloc(&TaskHandleType, 0);
×
174
    if (!obj) return NULL;
×
175
    new (&obj->future) std::shared_future<void>(std::move(handle.future));
×
176
    new (&obj->typed_future) std::shared_future<std::any>();
×
177
    new (&obj->name) std::string(std::move(handle.name));
×
178
    obj->has_typed_future = false;
×
179
    obj->task_id = handle.id;
×
180
    return (PyObject *)obj;
×
UNCOV
181
}
×
182

183
PyObject *create_typed_task_handle(std::shared_future<void> void_future,
×
184
                                   std::shared_future<std::any> typed_future,
185
                                   dftracer::utils::TaskIndex id,
186
                                   std::string name) {
UNCOV
187
    TaskHandleObject *obj =
×
188
        (TaskHandleObject *)TaskHandleType.tp_alloc(&TaskHandleType, 0);
×
189
    if (!obj) return NULL;
×
190
    new (&obj->future) std::shared_future<void>(std::move(void_future));
×
191
    new (&obj->typed_future)
×
192
        std::shared_future<std::any>(std::move(typed_future));
×
193
    new (&obj->name) std::string(std::move(name));
×
194
    obj->has_typed_future = true;
×
195
    obj->task_id = id;
×
196
    return (PyObject *)obj;
×
UNCOV
197
}
×
198

199
int init_task_handle(PyObject *m) {
1✔
200
    if (register_type(m, &TaskHandleType, "TaskHandle") < 0) return -1;
1!
201
    return 0;
1✔
202
}
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