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

llnl / dftracer-utils / 28398085302

29 Jun 2026 07:43PM UTC coverage: 50.067% (-2.2%) from 52.278%
28398085302

Pull #83

github

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

16342 of 44293 branches covered (36.9%)

Branch coverage included in aggregate %.

613 of 1132 new or added lines in 52 files covered. (54.15%)

687 existing lines in 116 files now uncovered.

21698 of 31685 relevant lines covered (68.48%)

12958.83 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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