DAWorkbench 0.0.1
DAWorkbench API
载入中...
搜索中...
未找到
DAPybind11QtCaster.hpp
1#ifndef DAPYBIND11QTCASTER_HPP
2#define DAPYBIND11QTCASTER_HPP
3#include "DAPybind11InQt.h"
4#include <QString>
5#include <QList>
6#include <QDateTime>
7#include <QList>
8#include <QVector>
9#include <QSet>
10#include <QHash>
11#include <QMap>
12
13#include <QVariant>
14
15namespace pybind11
16{
17namespace detail
18{
19
20// QString 转换器 - 优化版
21template<>
22struct type_caster< QString >
23{
24 PYBIND11_TYPE_CASTER(QString, _("str"));
25
26 bool load(handle src, bool convert)
27 {
28 if (!src)
29 return false;
30
31 // 处理Unicode字符串
32 if (PyUnicode_Check(src.ptr())) {
33 Py_ssize_t size;
34 const char* data = PyUnicode_AsUTF8AndSize(src.ptr(), &size);
35 if (data) {
36 value = QString::fromUtf8(data, size);
37 return true;
38 }
39 }
40 // 处理bytes对象
41 else if (convert && PyBytes_Check(src.ptr())) {
42 char* data;
43 Py_ssize_t size;
44 if (PyBytes_AsStringAndSize(src.ptr(), &data, &size) != -1) {
45 value = QString::fromUtf8(data, size);
46 return true;
47 }
48 }
49 return false;
50 }
51
52 static handle cast(const QString& src, return_value_policy /* policy */, handle /* parent */)
53 {
54 QByteArray utf8 = src.toUtf8();
55 return PyUnicode_FromStringAndSize(utf8.constData(), utf8.size());
56 }
57};
58
59// ============================================================================
60// QByteArray 转换器
61// ============================================================================
62template<>
63struct type_caster< QByteArray >
64{
65 PYBIND11_TYPE_CASTER(QByteArray, _("bytes"));
66
67 bool load(handle src, bool convert)
68 {
69 if (!src)
70 return false;
71
72 // 处理 None
73 if (src.is_none()) {
74 value = QByteArray();
75 return true;
76 }
77
78 // 处理 bytes 对象
79 if (PyBytes_Check(src.ptr())) {
80 char* data;
81 Py_ssize_t size;
82
83 if (PyBytes_AsStringAndSize(src.ptr(), &data, &size) != -1) {
84 // 创建 QByteArray,复制数据
85 value = QByteArray(data, size);
86 return true;
87 }
88 return false;
89 }
90
91 // 处理 bytearray 对象
92 if (PyByteArray_Check(src.ptr())) {
93 char* data;
94 Py_ssize_t size;
95
96 // 获取 bytearray 的数据指针和大小
97 data = PyByteArray_AS_STRING(src.ptr());
98 size = PyByteArray_GET_SIZE(src.ptr());
99
100 if (data && size >= 0) {
101 // 创建 QByteArray,复制数据
102 value = QByteArray(data, size);
103 return true;
104 }
105 return false;
106 }
107
108 // 如果允许转换,尝试从字符串转换
109 if (convert && PyUnicode_Check(src.ptr())) {
110 try {
111 // 将 Unicode 字符串转换为 UTF-8 编码的 QByteArray
112 Py_ssize_t size;
113 const char* data = PyUnicode_AsUTF8AndSize(src.ptr(), &size);
114 if (data) {
115 value = QByteArray(data, size);
116 return true;
117 }
118 } catch (...) {
119 return false;
120 }
121 }
122
123 // 如果允许转换,尝试从整数列表转换
124 if (convert && (PyList_Check(src.ptr()) || PyTuple_Check(src.ptr()))) {
125 try {
126 pybind11::sequence seq = reinterpret_borrow< pybind11::sequence >(src);
127 QByteArray byte_array;
128
129 for (size_t i = 0; i < seq.size(); ++i) {
130 pybind11::handle item = seq[ i ];
131
132 // 每个元素必须是 0-255 的整数
133 if (PyLong_Check(item.ptr())) {
134 long val = PyLong_AsLong(item.ptr());
135 if (val >= 0 && val <= 255) {
136 byte_array.append(static_cast< char >(val));
137 } else {
138 return false;
139 }
140 } else {
141 return false;
142 }
143 }
144
145 value = byte_array;
146 return true;
147 } catch (...) {
148 return false;
149 }
150 }
151
152 return false;
153 }
154
155 static handle cast(const QByteArray& src, return_value_policy /* policy */, handle /* parent */)
156 {
157 if (src.isNull()) {
158 Py_RETURN_NONE;
159 }
160
161 // 将 QByteArray 转换为 Python bytes 对象
162 // 使用 PyBytes_FromStringAndSize 可以正确处理包含空字节的数据
163 return PyBytes_FromStringAndSize(src.constData(), src.size());
164
165 // 如果希望返回 bytearray(可变)而不是 bytes(不可变),可以使用以下代码:
166 // return PyByteArray_FromStringAndSize(src.constData(), src.size());
167 }
168};
169
170// QDate 转换器 - 修复静态变量问题
171template<>
172struct type_caster< QDate >
173{
174 PYBIND11_TYPE_CASTER(QDate, _("datetime.date"));
175
176 // 延迟加载datetime模块
177 static pybind11::object& get_date_type()
178 {
179 static pybind11::object date_type = []() { return pybind11::module::import("datetime").attr("date"); }();
180 return date_type;
181 }
182
183 bool load(handle src, bool convert)
184 {
185 if (!src)
186 return false;
187
188 if (pybind11::isinstance(src, get_date_type())) {
189 int year = src.attr("year").cast< int >();
190 int month = src.attr("month").cast< int >();
191 int day = src.attr("day").cast< int >();
192
193 if (QDate::isValid(year, month, day)) {
194 value = QDate(year, month, day);
195 return true;
196 }
197 }
198 return false;
199 }
200
201 static handle cast(const QDate& src, return_value_policy /* policy */, handle /* parent */)
202 {
203 if (!src.isValid()) {
204 Py_RETURN_NONE;
205 }
206 return get_date_type()(src.year(), src.month(), src.day()).release();
207 }
208};
209
210// QTime 转换器
211template<>
212struct type_caster< QTime >
213{
214 PYBIND11_TYPE_CASTER(QTime, _("datetime.time"));
215
216 static pybind11::object& get_time_type()
217 {
218 static pybind11::object time_type = []() { return pybind11::module::import("datetime").attr("time"); }();
219 return time_type;
220 }
221
222 bool load(handle src, bool convert)
223 {
224 if (!src)
225 return false;
226
227 if (pybind11::isinstance(src, get_time_type())) {
228 int hour = src.attr("hour").cast< int >();
229 int minute = src.attr("minute").cast< int >();
230 int second = src.attr("second").cast< int >();
231 int microsecond = src.attr("microsecond").cast< int >();
232
233 int msec = microsecond / 1000;
234 if (QTime::isValid(hour, minute, second, msec)) {
235 value = QTime(hour, minute, second, msec);
236 return true;
237 }
238 }
239 return false;
240 }
241
242 static handle cast(const QTime& src, return_value_policy /* policy */, handle /* parent */)
243 {
244 if (!src.isValid()) {
245 Py_RETURN_NONE;
246 }
247 return get_time_type()(src.hour(), src.minute(), src.second(), src.msec() * 1000).release();
248 }
249};
250
251// QDateTime 转换器
252template<>
253struct type_caster< QDateTime >
254{
255 PYBIND11_TYPE_CASTER(QDateTime, _("datetime.datetime"));
256
257 static pybind11::object& get_datetime_type()
258 {
259 static pybind11::object datetime_type = []() -> pybind11::object {
260 try {
261 return pybind11::module::import("datetime").attr("datetime");
262 } catch (...) {
263 return pybind11::none();
264 }
265 }();
266 return datetime_type;
267 }
268 static pybind11::object& get_pandas_timestamp_type()
269 {
270 static pybind11::object pd_Timestamp = []() -> pybind11::object {
271 try {
272 return pybind11::module::import("pandas").attr("Timestamp");
273 } catch (...) {
274 return pybind11::none();
275 }
276 }();
277 return pd_Timestamp;
278 }
279 static pybind11::object& get_numpy_timestamp_type()
280 {
281 static pybind11::object np_datetime64 = []() -> pybind11::object {
282 try {
283 return pybind11::module::import("numpy").attr("datetime64");
284 } catch (...) {
285 return pybind11::none();
286 }
287 }();
288 return np_datetime64;
289 }
290 bool load(pybind11::handle src, bool convert)
291 {
292 if (!src) {
293 return false;
294 }
295 static pybind11::object& datetime_type = get_datetime_type();
296 if (!datetime_type.is_none() && pybind11::isinstance(src, datetime_type)) {
297 try {
298 // 使用 timestamp() 方法,它自动处理时区转换
299 pybind11::object timestamp = src.attr("timestamp");
300 double ts = timestamp().cast< double >();
301 qint64 msecs_since_epoch = static_cast< qint64 >(ts * 1000);
302
303 // 检查是否有时区信息
304 pybind11::object tzinfo = src.attr("tzinfo");
305 bool has_tzinfo = !tzinfo.is_none();
306
307 if (has_tzinfo) {
308 // 有时区信息,使用 timestamp() 方法,它自动处理时区转换
309 pybind11::object timestamp = src.attr("timestamp");
310 double ts = timestamp().cast< double >();
311 qint64 msecs_since_epoch = static_cast< qint64 >(ts * 1000);
312 value = QDateTime::fromMSecsSinceEpoch(msecs_since_epoch, Qt::UTC);
313 } else {
314 // naive datetime,直接从属性构建 QDateTime(不经过 timestamp 转换)
315 int year = src.attr("year").cast< int >();
316 int month = src.attr("month").cast< int >();
317 int day = src.attr("day").cast< int >();
318 int hour = src.attr("hour").cast< int >();
319 int minute = src.attr("minute").cast< int >();
320 int second = src.attr("second").cast< int >();
321 int microsecond = src.attr("microsecond").cast< int >();
322 int msec = microsecond / 1000;
323
324 QDate date(year, month, day);
325 QTime time(hour, minute, second, msec);
326
327 if (date.isValid() && time.isValid()) {
328 // 创建本地时间的 QDateTime
329 value = QDateTime(date, time);
330 return true;
331 }
332 }
333 return true;
334 } catch (...) {
335 return false;
336 }
337 }
338 static pybind11::object& np_timestamp = get_numpy_timestamp_type();
339 if (!np_timestamp.is_none() && pybind11::isinstance(src, np_timestamp)) {
340 // numpy datetime64
341 try {
342 int64_t ns = src.attr("astype")("datetime64[ns]").attr("view")("int64").cast< int64_t >();
343 value = QDateTime::fromMSecsSinceEpoch(ns / 1000000, Qt::UTC);
344 return true;
345 } catch (...) {
346 return false;
347 }
348 }
349
350 static pybind11::object& pd_timestamp = get_pandas_timestamp_type();
351 if (!pd_timestamp.is_none() && pybind11::isinstance(src, pd_timestamp)) {
352 // pandas Timestamp
353 try {
354 // pandas Timestamp 有自己的 tz 属性
355 pybind11::object tz = src.attr("tz");
356 bool has_tz = !tz.is_none();
357
358 if (has_tz) {
359 // 有时区信息,使用 UTC
360 double ts = src.attr("timestamp")().cast< double >();
361 value = QDateTime::fromMSecsSinceEpoch(static_cast< qint64 >(ts * 1000), Qt::UTC);
362 } else {
363 // 无时区信息,当作本地时间处理
364 // 对于 pandas Timestamp,我们使用 to_pydatetime() 转换为 python datetime,然后按照上面的逻辑处理
365 pybind11::object py_dt = src.attr("to_pydatetime")();
366 return load(py_dt, convert);
367 }
368 return true;
369 } catch (...) {
370 return false;
371 }
372 }
373 // 所有方法都失败
374 return false;
375 }
376
377 static pybind11::handle
378 cast(const QDateTime& src, pybind11::return_value_policy /* policy */, pybind11::handle /* parent */)
379 {
380 if (!src.isValid()) {
381 Py_RETURN_NONE;
382 }
383 /* 直接拿“墙上时间”戳,不再 toUTC() */
384 qint64 ms = src.toMSecsSinceEpoch();
385 double ts = ms / 1000.0;
386 try {
387 object datetime_type = module_::import("datetime").attr("datetime");
388 return datetime_type.attr("fromtimestamp")(ts).release();
389 } catch (...) {
390 Py_RETURN_NONE;
391 }
392 }
393};
394
395// ============================================================================
396// QList<T> 转换器
397// ============================================================================
398template< typename T >
399struct type_caster< QList< T > >
400{
401 using Native = QList< T >;
402 PYBIND11_TYPE_CASTER(Native, _("List"));
403
404 using value_conv = make_caster< T >;
405
406 bool load(handle src, bool convert)
407 {
408 if (!isinstance< list >(src)) {
409 return false;
410 }
411
412 auto l = reinterpret_borrow< list >(src);
413 value.clear();
414 value.reserve(static_cast< int >(l.size()));
415
416 for (auto it = l.begin(); it != l.end(); ++it) {
417 value_conv conv;
418 if (!conv.load(*it, convert)) {
419 return false;
420 }
421 value.append(cast_op< T >(conv));
422 }
423 return true;
424 }
425
426 static handle cast(const Native& src, return_value_policy policy, handle parent)
427 {
428 list l(src.size());
429 size_t index = 0;
430
431 for (const T& item : src) {
432 auto value_conv = reinterpret_steal< object >(value_conv::cast(item, policy, parent));
433 if (!value_conv) {
434 return handle();
435 }
436 PyList_SET_ITEM(l.ptr(), index++, value_conv.release().ptr());
437 }
438 return l.release();
439 }
440};
441
442// ============================================================================
443// QVector<T> 转换器 (现代版)
444// ============================================================================
445#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
446template< typename T >
447struct type_caster< QVector< T > >
448{
449 using Native = QVector< T >;
450 PYBIND11_TYPE_CASTER(Native, _("List"));
451
452 using value_conv = make_caster< T >;
453
454 bool load(handle src, bool convert)
455 {
456 if (!isinstance< list >(src)) {
457 return false;
458 }
459
460 auto l = reinterpret_borrow< list >(src);
461 value.clear();
462 value.reserve(static_cast< int >(l.size()));
463
464 for (auto it = l.begin(); it != l.end(); ++it) {
465 value_conv conv;
466 if (!conv.load(*it, convert)) {
467 return false;
468 }
469 value.append(cast_op< T >(conv));
470 }
471 return true;
472 }
473
474 static handle cast(const Native& src, return_value_policy policy, handle parent)
475 {
476 list l(src.size());
477 size_t index = 0;
478
479 for (const T& item : src) {
480 auto value_conv = reinterpret_steal< object >(value_conv::cast(item, policy, parent));
481 if (!value_conv) {
482 return handle();
483 }
484 PyList_SET_ITEM(l.ptr(), index++, value_conv.release().ptr());
485 }
486 return l.release();
487 }
488};
489#endif
490// ============================================================================
491// QSet<T> 转换器
492// ============================================================================
493template< typename T >
494struct type_caster< QSet< T > >
495{
496 using Native = QSet< T >;
497 PYBIND11_TYPE_CASTER(Native, _("Set"));
498
499 using value_conv = make_caster< T >;
500
501 bool load(handle src, bool convert)
502 {
503 // 尝试作为集合加载
504 if (isinstance< set >(src)) {
505 auto s = reinterpret_borrow< set >(src);
506 value.clear();
507
508 for (auto it = s.begin(); it != s.end(); ++it) {
509 value_conv conv;
510 if (!conv.load(*it, convert)) {
511 return false;
512 }
513 value.insert(cast_op< T >(conv));
514 }
515 return true;
516 }
517
518 // 如果不是集合,尝试作为列表加载(允许从列表转换)
519 if (isinstance< list >(src)) {
520 auto l = reinterpret_borrow< list >(src);
521 value.clear();
522
523 for (auto it = l.begin(); it != l.end(); ++it) {
524 value_conv conv;
525 if (!conv.load(*it, convert)) {
526 return false;
527 }
528 value.insert(cast_op< T >(conv));
529 }
530 return true;
531 }
532
533 return false;
534 }
535
536 static handle cast(const Native& src, return_value_policy policy, handle parent)
537 {
538 pybind11::set s;
539
540 for (const T& item : src) {
541 auto value_conv = reinterpret_steal< object >(value_conv::cast(item, policy, parent));
542 if (!value_conv) {
543 return handle();
544 }
545
546 if (!s.add(value_conv)) {
547 return handle();
548 }
549 }
550
551 return s.release();
552 }
553};
554
555// ============================================================================
556// QHash<K, V> 转换器
557// ============================================================================
558template< typename K, typename V >
559struct type_caster< QHash< K, V > >
560{
561 using Native = QHash< K, V >;
562 PYBIND11_TYPE_CASTER(Native, _("Dict"));
563
564 using key_conv = make_caster< K >;
565 using value_conv = make_caster< V >;
566
567 bool load(handle src, bool convert)
568 {
569 if (!isinstance< dict >(src)) {
570 return false;
571 }
572
573 auto d = reinterpret_borrow< dict >(src);
574 value.clear();
575
576 for (auto it = d.begin(); it != d.end(); ++it) {
577 key_conv ck;
578 value_conv cv;
579
580 if (!ck.load(it->first, convert) || !cv.load(it->second, convert)) {
581 return false;
582 }
583
584 value.insert(cast_op< K >(ck), cast_op< V >(cv));
585 }
586 return true;
587 }
588
589 static handle cast(const Native& src, return_value_policy policy, handle parent)
590 {
591 dict d;
592
593 for (auto it = src.begin(); it != src.end(); ++it) {
594 auto k = reinterpret_steal< object >(key_conv::cast(it.key(), policy, parent));
595 auto v = reinterpret_steal< object >(value_conv::cast(it.value(), policy, parent));
596
597 if (!k || !v) {
598 return handle();
599 }
600
601 d[ k ] = v;
602 }
603
604 return d.release();
605 }
606};
607
608// ============================================================================
609// QMap<K, V> 转换器
610// ============================================================================
611template< typename K, typename V >
612struct type_caster< QMap< K, V > >
613{
614 using Native = QMap< K, V >;
615 PYBIND11_TYPE_CASTER(Native, _("Dict"));
616
617 using key_conv = make_caster< K >;
618 using value_conv = make_caster< V >;
619
620 bool load(handle src, bool convert)
621 {
622 if (!isinstance< dict >(src)) {
623 return false;
624 }
625
626 auto d = reinterpret_borrow< dict >(src);
627 value.clear();
628
629 for (auto it = d.begin(); it != d.end(); ++it) {
630 key_conv ck;
631 value_conv cv;
632
633 if (!ck.load(it->first, convert) || !cv.load(it->second, convert)) {
634 return false;
635 }
636
637 value.insert(cast_op< K >(ck), cast_op< V >(cv));
638 }
639 return true;
640 }
641
642 static handle cast(const Native& src, return_value_policy policy, handle parent)
643 {
644 dict d;
645
646 for (auto it = src.begin(); it != src.end(); ++it) {
647 auto k = reinterpret_steal< object >(key_conv::cast(it.key(), policy, parent));
648 auto v = reinterpret_steal< object >(value_conv::cast(it.value(), policy, parent));
649
650 if (!k || !v) {
651 return handle();
652 }
653
654 d[ k ] = v;
655 }
656
657 return d.release();
658 }
659};
660
661// ============================================================================
662// QVariant 转换器
663// ============================================================================
664template<>
665struct type_caster< QVariant >
666{
667 PYBIND11_TYPE_CASTER(QVariant, _("Any"));
668
669 // 辅助函数:检查是否为 None 或为空
670 static bool is_none_or_empty(handle src)
671 {
672 return src.is_none() || (PyObject_Size(src.ptr()) == 0 && PyErr_Occurred() == nullptr);
673 }
674
675 // 辅助函数:判断是否是 numpy 对象
676 static bool is_numpy_array(handle src)
677 {
678 try {
679 static pybind11::object numpy_module = []() -> pybind11::object {
680 try {
681 return pybind11::module::import("numpy");
682 } catch (...) {
683 return pybind11::none();
684 }
685 }();
686
687 if (!numpy_module.is_none()) {
688 static pybind11::object ndarray_type = numpy_module.attr("ndarray");
689 static pybind11::object generic_type = numpy_module.attr("generic");
690 return pybind11::isinstance(src, ndarray_type) || pybind11::isinstance(src, generic_type);
691 }
692 } catch (...) {
693 // 忽略异常,说明 numpy 不可用
694 }
695 return false;
696 }
697
698 // 处理 numpy 数组或标量
699 bool handle_numpy_object(handle src)
700 {
701 try {
702 pybind11::object np_obj = reinterpret_borrow< object >(src);
703 pybind11::dtype dt = np_obj.attr("dtype");
704 char dtype_char = dt.char_();
705
706 // 获取 shape 和 ndim
707 pybind11::tuple shape = np_obj.attr("shape");
708 std::size_t ndim = pybind11::len(shape);
709
710 // 处理标量(0维数组)
711 if (ndim == 0) {
712 // 使用 item() 方法获取标量值
713 pybind11::object scalar = np_obj.attr("item")();
714
715 switch (dtype_char) {
716 case '?': // bool
717 value = scalar.cast< bool >();
718 return true;
719 case 'b': // int8
720 value = QChar(static_cast< char >(scalar.cast< int >()));
721 return true;
722 case 'h': // int16
723 case 'l': // int32 (通常)
724 value = scalar.cast< int >();
725 return true;
726 case 'q': // int64
727 value = scalar.cast< long long >();
728 return true;
729 case 'B': // uint8
730 value = QChar(static_cast< unsigned char >(scalar.cast< int >()));
731 return true;
732 case 'H': // uint16
733 case 'L': // uint32 (通常)
734 value = scalar.cast< unsigned int >();
735 return true;
736 case 'Q': // uint64
737 value = scalar.cast< unsigned long long >();
738 return true;
739 case 'e': // float16 (半精度)
740 case 'f': // float32
741 value = scalar.cast< float >();
742 return true;
743 case 'd': // float64
744 value = scalar.cast< double >();
745 return true;
746 case 'F': // complex64
747 case 'D': // complex128
748 // 复数转换为 QString
749 value = QString::fromStdString(pybind11::str(scalar));
750 return true;
751 case 'U': // Unicode 字符串
752 {
753 // 获取字符串长度
754 pybind11::object item = np_obj.attr("item")();
755 QString str_val;
756
757 // 尝试不同的转换方式
758 if (PyUnicode_Check(item.ptr())) {
759 Py_ssize_t size;
760 const char* data = PyUnicode_AsUTF8AndSize(item.ptr(), &size);
761 if (data) {
762 str_val = QString::fromUtf8(data, size);
763 }
764 } else {
765 str_val = QString::fromStdString(pybind11::str(item));
766 }
767
768 value = str_val;
769 return true;
770 }
771 case 'S': // bytes 字符串
772 {
773 pybind11::object item = np_obj.attr("item")();
774 QByteArray byte_val;
775
776 if (PyBytes_Check(item.ptr())) {
777 char* data;
778 Py_ssize_t size;
779 if (PyBytes_AsStringAndSize(item.ptr(), &data, &size) != -1) {
780 byte_val = QByteArray(data, size);
781 }
782 } else {
783 byte_val = QByteArray(pybind11::str(item).cast< std::string >().c_str());
784 }
785
786 value = byte_val;
787 return true;
788 }
789 case 'M': // datetime64
790 {
791 // 转换为 QDateTime
792 pybind11::object item = np_obj.attr("item")();
793
794 // 尝试作为 Python datetime 对象处理
795 try {
796 static pybind11::object datetime_type = []() -> pybind11::object {
797 try {
798 return pybind11::module::import("datetime").attr("datetime");
799 } catch (...) {
800 return pybind11::none();
801 }
802 }();
803
804 if (!datetime_type.is_none() && pybind11::isinstance(item, datetime_type)) {
805 QDateTime dt_val = item.cast< QDateTime >();
806 value = dt_val;
807 return true;
808 }
809 } catch (...) {
810 }
811
812 // 如果上面的方法失败,尝试使用时间戳
813 try {
814 // numpy.datetime64 可以转换为整数时间戳
815 pybind11::object timestamp = item.attr("astype")("datetime64[ms]");
816 int64_t ms = pybind11::cast< int64_t >(timestamp.attr("view")("int64"));
817 value = QDateTime::fromMSecsSinceEpoch(ms);
818 return true;
819 } catch (...) {
820 // 转换为字符串
821 QString str_val = QString::fromStdString(pybind11::str(item));
822 value = str_val;
823 return true;
824 }
825 }
826 case 'm': // timedelta64
827 {
828 // 转换为 QString
829 QString str_val = QString::fromStdString(pybind11::str(np_obj.attr("item")()));
830 value = str_val;
831 return true;
832 }
833 case 'V': // void (记录数组)
834 {
835 // 转换为 QByteArray
836 QByteArray byte_val = QByteArray(pybind11::str(np_obj.attr("item")()).cast< std::string >().c_str());
837 value = byte_val;
838 return true;
839 }
840 case 'O': // Python 对象
841 {
842 // 递归转换
843 pybind11::object item = np_obj.attr("item")();
845 if (caster.load(item, true)) {
846 value = caster.value;
847 return true;
848 }
849 return false;
850 }
851 default:
852 // 未知类型,尝试转换为字符串
853 value = QString::fromStdString(pybind11::str(np_obj.attr("item")()));
854 return true;
855 }
856 }
857 // 处理多维数组(转换为 QVariantList)
858 else {
859 // 获取数组大小
860 int total_size = 1;
861 for (std::size_t i = 0; i < ndim; ++i) {
862 total_size *= shape[ i ].cast< int >();
863 }
864 // 将 numpy 数组转换为 Python 列表
865 pybind11::list py_list = np_obj.attr("tolist")();
866
867 // 递归转换为 QVariantList
868 QVariantList qt_list;
869 qt_list.reserve(total_size);
870
871 for (auto item : py_list) {
873 if (caster.load(item, true)) {
874 qt_list.append(caster.value);
875 } else {
876 return false;
877 }
878 }
879
880 value = qt_list;
881 return true;
882 }
883 } catch (...) {
884 // numpy 转换失败
885 return false;
886 }
887
888 return false;
889 }
890
891 // 从 Python 对象加载到 QVariant
892 bool load(handle src, bool convert)
893 {
894 if (!src)
895 return false;
896
897 // 处理 None
898 if (src.is_none()) {
899 value = QVariant();
900 return true;
901 }
902
903 // 首先检查是否是 numpy 对象
904 if (is_numpy_array(src)) {
905 return handle_numpy_object(src);
906 }
907 // 尝试各种类型的转换
908 try {
909 // 1. 整数类型
910 if (PyLong_Check(src.ptr())) {
911 // 尝试作为 int 加载
912 try {
913 int int_val = src.cast< int >();
914 value = QVariant(int_val);
915 return true;
916 } catch (...) {
917 // 如果 int 失败,尝试 long long
918 try {
919 qlonglong ll_val = src.cast< qlonglong >();
920 value = QVariant(ll_val);
921 return true;
922 } catch (...) {
923 // 如果 long long 也失败,尝试 unsigned long long
924 try {
925 qulonglong ull_val = src.cast< qulonglong >();
926 value = QVariant(ull_val);
927 return true;
928 } catch (...) {
929 // 继续尝试其他类型
930 }
931 }
932 }
933 }
934
935 // 2. 浮点数
936 if (PyFloat_Check(src.ptr())) {
937 try {
938 double double_val = src.cast< double >();
939 value = QVariant(double_val);
940 return true;
941 } catch (...) {
942 try {
943 float float_val = src.cast< float >();
944 value = QVariant(float_val);
945 return true;
946 } catch (...) {
947 // 继续尝试其他类型
948 }
949 }
950 }
951
952 // 3. 布尔值
953 if (PyBool_Check(src.ptr())) {
954 bool bool_val = src.cast< bool >();
955 value = QVariant(bool_val);
956 return true;
957 }
958
959 // 4. 字符串
960 if (PyUnicode_Check(src.ptr())) {
961 try {
962 QString str_val = src.cast< QString >();
963 value = QVariant(str_val);
964 return true;
965 } catch (...) {
966 // 继续尝试其他类型
967 }
968 }
969
970 // 5. bytes/bytearray
971 if (PyBytes_Check(src.ptr()) || PyByteArray_Check(src.ptr())) {
972 try {
973 QByteArray byte_val = src.cast< QByteArray >();
974 value = QVariant(byte_val);
975 return true;
976 } catch (...) {
977 // 继续尝试其他类型
978 }
979 }
980
981 // 6. 列表/元组
982 if (PyList_Check(src.ptr()) || PyTuple_Check(src.ptr())) {
983 // 尝试作为 QVariantList 加载
984 try {
985 QVariantList list_val = src.cast< QVariantList >();
986 value = QVariant(list_val);
987 return true;
988 } catch (...) {
989 return false;
990 }
991 }
992
993 // 7. 字典
994 if (PyDict_Check(src.ptr())) {
995 // 尝试作为 QVariantMap
996 try {
997 QVariantMap map_val = src.cast< QVariantMap >();
998 value = QVariant(map_val);
999 return true;
1000 } catch (...) {
1001 // 尝试作为 QVariantHash
1002 try {
1003 QVariantHash hash_val = src.cast< QVariantHash >();
1004 value = QVariant(hash_val);
1005 return true;
1006 } catch (...) {
1007 // 继续尝试其他类型
1008 }
1009 }
1010 }
1011
1012 // 8. 集合
1013 if (PySet_Check(src.ptr())) {
1014 try {
1015 QVariantList list_val;
1016 auto set_obj = reinterpret_borrow< set >(src);
1017 for (auto item : set_obj) {
1019 if (caster.load(item, convert)) {
1020 list_val.append(caster.value);
1021 } else {
1022 return false;
1023 }
1024 }
1025 value = QVariant(list_val);
1026 return true;
1027 } catch (...) {
1028 // 继续尝试其他类型
1029 }
1030 }
1031
1032 // 9. 日期和时间类型
1033 // 检查是否是 datetime.datetime
1034 try {
1035 static pybind11::object datetime_type = []() {
1036 return pybind11::module::import("datetime").attr("datetime");
1037 }();
1038
1039 if (pybind11::isinstance(src, datetime_type)) {
1040 QDateTime dt_val = src.cast< QDateTime >();
1041 value = QVariant(dt_val);
1042 return true;
1043 }
1044 } catch (...) {
1045 }
1046
1047 // 检查是否是 datetime.date
1048 try {
1049 static pybind11::object date_type = []() { return pybind11::module::import("datetime").attr("date"); }();
1050
1051 if (pybind11::isinstance(src, date_type)) {
1052 QDate date_val = src.cast< QDate >();
1053 value = QVariant(date_val);
1054 return true;
1055 }
1056 } catch (...) {
1057 }
1058
1059 // 检查是否是 datetime.time
1060 try {
1061 static pybind11::object time_type = []() { return pybind11::module::import("datetime").attr("time"); }();
1062
1063 if (pybind11::isinstance(src, time_type)) {
1064 QTime time_val = src.cast< QTime >();
1065 value = QVariant(time_val);
1066 return true;
1067 }
1068 } catch (...) {
1069 }
1070
1071 // 如果以上都不行,尝试通用转换
1072 if (convert) {
1073 try {
1074 // 最后尝试:转换成 QString
1075 QString str_val = src.cast< QString >();
1076 value = QVariant(str_val);
1077 return true;
1078 } catch (...) {
1079 }
1080 }
1081
1082 // 给一个无效的variant
1083 value = QVariant();
1084 return true;
1085 } catch (...) {
1086 // 捕获异常,但不抛出,只是返回转换失败
1087 return false;
1088 }
1089
1090 return false;
1091 }
1092
1093 // 将 QVariant 转换为 Python 对象
1094 static handle cast(const QVariant& src, return_value_policy policy, handle parent)
1095 {
1096 if (!src.isValid() || src.isNull()) {
1097 Py_RETURN_NONE;
1098 }
1099
1100 try {
1101 // 根据 QVariant 的类型进行转换
1102 int type_id = src.userType();
1103
1104 // 检查 QMetaType 类型
1105 switch (type_id) {
1106 case QMetaType::UnknownType:
1107 Py_RETURN_NONE;
1108
1109 // 基本数值类型
1110 case QMetaType::Int:
1111 return pybind11::cast(src.toInt()).release();
1112 case QMetaType::UInt:
1113 return pybind11::cast(src.toUInt()).release();
1114 case QMetaType::LongLong:
1115 return pybind11::cast(src.toLongLong()).release();
1116 case QMetaType::ULongLong:
1117 return pybind11::cast(src.toULongLong()).release();
1118 case QMetaType::Double:
1119 return pybind11::cast(src.toDouble()).release();
1120 case QMetaType::Float:
1121 return pybind11::cast(src.toFloat()).release();
1122 case QMetaType::Bool:
1123 return pybind11::cast(src.toBool()).release();
1124
1125 // 字符串类型
1126 case QMetaType::QString:
1127 return pybind11::cast(src.toString()).release();
1128 case QMetaType::QByteArray:
1129 return pybind11::cast(src.toByteArray()).release();
1130 case QMetaType::QChar:
1131 return pybind11::cast(src.toChar()).release();
1132
1133 // 日期时间类型
1134 case QMetaType::QDate:
1135 return pybind11::cast(src.toDate()).release();
1136 case QMetaType::QTime:
1137 return pybind11::cast(src.toTime()).release();
1138 case QMetaType::QDateTime:
1139 return pybind11::cast(src.toDateTime()).release();
1140 // 容器类型
1141 case QMetaType::QVariantList: {
1142 QVariantList list = src.toList();
1143 pybind11::list py_list;
1144 for (const QVariant& item : list) {
1145 py_list.append(cast(item, policy, parent));
1146 }
1147 return py_list.release();
1148 }
1149
1150 case QMetaType::QVariantMap: {
1151 QVariantMap map = src.toMap();
1152 pybind11::dict py_dict;
1153 for (auto it = map.begin(); it != map.end(); ++it) {
1154 py_dict[ pybind11::cast(it.key()) ] = cast(it.value(), policy, parent);
1155 }
1156 return py_dict.release();
1157 }
1158
1159 case QMetaType::QVariantHash: {
1160 QVariantHash hash = src.toHash();
1161 pybind11::dict py_dict;
1162 for (auto it = hash.begin(); it != hash.end(); ++it) {
1163 py_dict[ pybind11::cast(it.key()) ] = cast(it.value(), policy, parent);
1164 }
1165 return py_dict.release();
1166 }
1167
1168 // 处理 QList<T> 类型
1169 default: {
1170 // 尝试检测是否是 QList<T> 类型
1171 const char* type_name = src.typeName();
1172 if (type_name) {
1173 QString type_str = QString::fromUtf8(type_name);
1174
1175 // QList<QString>
1176 if (type_str == "QList<QString>") {
1177 return pybind11::cast(src.value< QList< QString > >()).release();
1178 }
1179 // QList<int>
1180 else if (type_str == "QList<int>") {
1181 return pybind11::cast(src.value< QList< int > >()).release();
1182 }
1183 // QList<double>
1184 else if (type_str == "QList<double>") {
1185 return pybind11::cast(src.value< QList< double > >()).release();
1186 }
1187 // QVector<QString>
1188 else if (type_str == "QVector<QString>") {
1189 return pybind11::cast(src.value< QVector< QString > >()).release();
1190 }
1191 // 其他已知类型的 QList
1192 else if (type_str.startsWith("QList<") || type_str.startsWith("QVector<")) {
1193 // 对于未知类型的列表,转换为 Python 列表
1194 QVariantList list = src.toList();
1195 pybind11::list py_list;
1196 for (const QVariant& item : list) {
1197 py_list.append(cast(item, policy, parent));
1198 }
1199 return py_list.release();
1200 }
1201 // QMap 或 QHash
1202 else if (type_str.startsWith("QMap<") || type_str.startsWith("QHash<")) {
1203 // 转换为 Python 字典
1204 QVariantMap map = src.toMap();
1205 pybind11::dict py_dict;
1206 for (auto it = map.begin(); it != map.end(); ++it) {
1207 py_dict[ pybind11::cast(it.key()) ] = cast(it.value(), policy, parent);
1208 }
1209 return py_dict.release();
1210 }
1211 // QSet
1212 else if (type_str.startsWith("QSet<")) {
1213 // 转换为 Python 集合
1214 QVariantList list = src.toList();
1215 pybind11::set py_set;
1216 for (const QVariant& item : list) {
1217 py_set.add(cast(item, policy, parent));
1218 }
1219 return py_set.release();
1220 }
1221 }
1222
1223 // 如果以上都不匹配,尝试使用 toString()
1224 if (src.canConvert< QString >()) {
1225 return pybind11::cast(src.toString()).release();
1226 }
1227
1228 // 最后尝试:返回字符串表示
1229 return pybind11::cast(src.toString()).release();
1230 }
1231 }
1232 } catch (...) {
1233 // 如果转换失败,返回 None
1234 Py_RETURN_NONE;
1235 }
1236 }
1237};
1238
1239} // namespace detail
1240} // namespace pybind11
1241
1242// 辅助函数,方便手动转换
1243namespace DA
1244{
1245namespace PY
1246{
1247
1248// QString 转换函数
1249inline QString fromPyString(pybind11::handle py_str)
1250{
1251 return pybind11::cast< QString >(py_str);
1252}
1253
1254inline pybind11::object toPyObject(const QString& qt_str)
1255{
1256 return pybind11::cast(qt_str);
1257}
1258
1259// QDate 转换函数
1260inline QDate fromPyDate(pybind11::handle py_date)
1261{
1262 return pybind11::cast< QDate >(py_date);
1263}
1264
1265inline pybind11::object toPyObject(const QDate& qt_date)
1266{
1267 return pybind11::cast(qt_date);
1268}
1269
1270// QTime 转换函数
1271inline QTime fromPyTime(pybind11::handle py_time)
1272{
1273 return pybind11::cast< QTime >(py_time);
1274}
1275
1276inline pybind11::object toPyObject(const QTime& qt_time)
1277{
1278 return pybind11::cast(qt_time);
1279}
1280
1281// QDateTime 转换函数
1282inline QDateTime fromPyDateTime(pybind11::handle py_datetime)
1283{
1284 return pybind11::cast< QDateTime >(py_datetime);
1285}
1286
1287inline pybind11::object toPyObject(const QDateTime& qt_datetime)
1288{
1289 return pybind11::cast(qt_datetime);
1290}
1291
1292// 列表转换
1293template< typename T >
1294inline QList< T > fromPyList(pybind11::handle py_list)
1295{
1296 return pybind11::cast< QList< T > >(py_list);
1297}
1298
1299template< typename T >
1300inline pybind11::object toPyObject(const QList< T >& qt_list)
1301{
1302 return pybind11::cast(qt_list);
1303}
1304
1305// 向量转换
1306template< typename T >
1307inline QVector< T > fromPyVector(pybind11::handle py_list)
1308{
1309 return pybind11::cast< QVector< T > >(py_list);
1310}
1311
1312#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1313template< typename T >
1314inline pybind11::object toPyObject(const QVector< T >& qt_vector)
1315{
1316 return pybind11::cast(qt_vector);
1317}
1318#endif
1319
1320// 集合转换
1321template< typename T >
1322inline QSet< T > fromPySet(pybind11::handle py_set)
1323{
1324 return pybind11::cast< QSet< T > >(py_set);
1325}
1326
1327template< typename T >
1328inline pybind11::object toPyObject(const QSet< T >& qt_set)
1329{
1330 return pybind11::cast(qt_set);
1331}
1332
1333// 从列表创建集合
1334template< typename T >
1335inline QSet< T > fromPyListToSet(pybind11::handle py_list)
1336{
1337 return pybind11::cast< QSet< T > >(py_list);
1338}
1339
1340// 字典转换
1341template< typename K, typename V >
1342inline QHash< K, V > fromPyDict(pybind11::handle py_dict)
1343{
1344 return pybind11::cast< QHash< K, V > >(py_dict);
1345}
1346
1347template< typename K, typename V >
1348inline pybind11::object toPyObject(const QHash< K, V >& qt_hash)
1349{
1350 return pybind11::cast(qt_hash);
1351}
1352
1353template< typename K, typename V >
1354inline QMap< K, V > fromPyMap(pybind11::handle py_dict)
1355{
1356 return pybind11::cast< QMap< K, V > >(py_dict);
1357}
1358
1359template< typename K, typename V >
1360inline pybind11::object toPyObject(const QMap< K, V >& qt_map)
1361{
1362 return pybind11::cast(qt_map);
1363}
1364
1365// QVariant 转换函数
1366inline QVariant fromPyVariant(pybind11::handle py_obj)
1367{
1368 return pybind11::cast< QVariant >(py_obj);
1369}
1370
1371inline pybind11::object toPyObject(const QVariant& qt_var)
1372{
1373 return pybind11::cast(qt_var);
1374}
1375
1376inline pybind11::object toPyObject(const QVariant& qt_var, const pybind11::dtype& dt)
1377{
1378 return dt.attr("type")(toPyObject(qt_var));
1379}
1380
1381// 能转成 QDateTime 吗?
1382// 支持:datetime.datetime / pandas.Timestamp / numpy.datetime64
1383inline bool canCastToQDateTime(pybind11::handle src)
1384{
1385 if (!src)
1386 return false;
1387
1388 try {
1389 // 1. datetime.datetime
1390 static pybind11::object datetime_type = pybind11::module::import("datetime").attr("datetime");
1391 if (pybind11::isinstance(src, datetime_type))
1392 return true;
1393
1394 // 2. pandas.Timestamp
1395 static pybind11::object pd_Timestamp = []() -> pybind11::object {
1396 try {
1397 return pybind11::module::import("pandas").attr("Timestamp");
1398 } catch (...) {
1399 return pybind11::none();
1400 }
1401 }();
1402 if (!pd_Timestamp.is_none() && pybind11::isinstance(src, pd_Timestamp))
1403 return true;
1404
1405 // 3. numpy.datetime64
1406 static pybind11::object np_datetime64 = []() -> pybind11::object {
1407 try {
1408 return pybind11::module::import("numpy").attr("datetime64");
1409 } catch (...) {
1410 return pybind11::none();
1411 }
1412 }();
1413 if (!np_datetime64.is_none() && pybind11::isinstance(src, np_datetime64))
1414 return true;
1415 } catch (...) {
1416 }
1417 return false;
1418}
1419
1420inline bool canCastToQDate(pybind11::handle src)
1421{
1422 if (!src)
1423 return false;
1424 try {
1425 static pybind11::object date_type = pybind11::module::import("datetime").attr("date");
1426 return pybind11::isinstance(src, date_type);
1427 } catch (...) {
1428 }
1429 return false;
1430}
1431
1432inline bool canCastToQTime(pybind11::handle src)
1433{
1434 if (!src)
1435 return false;
1436 try {
1437 static pybind11::object time_type = pybind11::module::import("datetime").attr("time");
1438 return pybind11::isinstance(src, time_type);
1439 } catch (...) {
1440 }
1441 return false;
1442}
1443
1444inline bool canCastToQString(pybind11::handle src)
1445{
1446 return src && (PyUnicode_Check(src.ptr()) || PyBytes_Check(src.ptr()));
1447}
1448
1449} // namespace PY
1450} // namespace DA
1451#endif // DAPYBIND11QTCASTER_HPP
序列化类都是带异常的,使用中需要处理异常
Definition AppMainWindow.cpp:44
Definition DAPybind11QtCaster.hpp:666