373
379
A CppClass object takes care of generating the code for wrapping a C++ class
377
'PyTypeObject %(typestruct)s = {\n'
378
' PyObject_HEAD_INIT(NULL)\n'
379
' 0, /* ob_size */\n'
380
' (char *) "%(tp_name)s", /* tp_name */\n'
381
' %(tp_basicsize)s, /* tp_basicsize */\n'
382
' 0, /* tp_itemsize */\n'
384
' (destructor)%(tp_dealloc)s, /* tp_dealloc */\n'
385
' (printfunc)0, /* tp_print */\n'
386
' (getattrfunc)%(tp_getattr)s, /* tp_getattr */\n'
387
' (setattrfunc)%(tp_setattr)s, /* tp_setattr */\n'
388
' (cmpfunc)%(tp_compare)s, /* tp_compare */\n'
389
' (reprfunc)%(tp_repr)s, /* tp_repr */\n'
390
' (PyNumberMethods*)%(tp_as_number)s, /* tp_as_number */\n'
391
' (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n'
392
' (PyMappingMethods*)%(tp_as_mapping)s, /* tp_as_mapping */\n'
393
' (hashfunc)%(tp_hash)s, /* tp_hash */\n'
394
' (ternaryfunc)%(tp_call)s, /* tp_call */\n'
395
' (reprfunc)%(tp_str)s, /* tp_str */\n'
396
' (getattrofunc)%(tp_getattro)s, /* tp_getattro */\n'
397
' (setattrofunc)%(tp_setattro)s, /* tp_setattro */\n'
398
' (PyBufferProcs*)%(tp_as_buffer)s, /* tp_as_buffer */\n'
399
' %(tp_flags)s, /* tp_flags */\n'
400
' %(tp_doc)s, /* Documentation string */\n'
401
' (traverseproc)%(tp_traverse)s, /* tp_traverse */\n'
402
' (inquiry)%(tp_clear)s, /* tp_clear */\n'
403
' (richcmpfunc)%(tp_richcompare)s, /* tp_richcompare */\n'
404
' %(tp_weaklistoffset)s, /* tp_weaklistoffset */\n'
405
' (getiterfunc)%(tp_iter)s, /* tp_iter */\n'
406
' (iternextfunc)%(tp_iternext)s, /* tp_iternext */\n'
407
' (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n'
408
' (struct PyMemberDef*)0, /* tp_members */\n'
409
' %(tp_getset)s, /* tp_getset */\n'
410
' NULL, /* tp_base */\n'
411
' NULL, /* tp_dict */\n'
412
' (descrgetfunc)%(tp_descr_get)s, /* tp_descr_get */\n'
413
' (descrsetfunc)%(tp_descr_set)s, /* tp_descr_set */\n'
414
' %(tp_dictoffset)s, /* tp_dictoffset */\n'
415
' (initproc)%(tp_init)s, /* tp_init */\n'
416
' (allocfunc)%(tp_alloc)s, /* tp_alloc */\n'
417
' (newfunc)%(tp_new)s, /* tp_new */\n'
418
' (freefunc)%(tp_free)s, /* tp_free */\n'
419
' (inquiry)%(tp_is_gc)s, /* tp_is_gc */\n'
420
' NULL, /* tp_bases */\n'
421
' NULL, /* tp_mro */\n'
422
' NULL, /* tp_cache */\n'
423
' NULL, /* tp_subclasses */\n'
424
' NULL, /* tp_weaklist */\n'
425
' (destructor) NULL /* tp_del */\n'
429
382
def __init__(self, name, parent=None, incref_method=None, decref_method=None,
430
383
automatic_type_narrowing=None, allow_subclassing=None,
431
384
is_singleton=False, outer_class=None,
617
576
def __repr__(self):
618
577
return "<pybindgen.CppClass %r>" % self.full_name
579
def add_binary_comparison_operator(self, operator):
581
Add support for a C++ binary comparison operator, such as == or <.
583
The binary operator is assumed to operate with both operands
584
of the type of the class, either by reference or by value.
586
@param operator: string indicating the name of the operator to
589
if not isinstance(operator, str):
590
raise TypeError("expected operator name as string")
591
if operator not in ['==', '!=', '<', '<=', '>', '>=']:
592
raise ValueError("The operator %r is invalid or not yet supported by PyBindGen" % (operator,))
593
self.binary_comparison_operators.add(operator)
595
def add_binary_numeric_operator(self, operator, result_cppclass=None,
596
left_cppclass=None, right_cppclass=None):
598
Add support for a C++ binary numeric operator, such as +, -, *, or /.
600
@param operator: string indicating the name of the operator to
603
@param result_cppclass: the CppClass object of the result type, assumed to be this class if omitted
604
@param left_cppclass: the CppClass object of the left operand type, assumed to be this class if omitted
605
@param right_cppclass: the CppClass object of the right operand type, assumed to be this class if omitted
607
if not isinstance(operator, str):
608
raise TypeError("expected operator name as string")
609
if operator not in ['+', '-', '*', '/']:
610
raise ValueError("The operator %r is invalid or not yet supported by PyBindGen" % (operator,))
612
l = self.binary_numeric_operators[operator]
615
self.binary_numeric_operators[operator] = l
616
if result_cppclass is None:
617
result_cppclass = self
618
if left_cppclass is None:
620
if right_cppclass is None:
621
right_cppclass = self
622
op = (result_cppclass, left_cppclass, right_cppclass)
621
626
def add_class(self, *args, **kwargs):
1443
1484
self._generate_destructor(code_sink, have_constructor)
1444
1485
if self.has_output_stream_operator:
1445
1486
self._generate_str(code_sink)
1488
#self._generate_tp_hash(code_sink)
1489
#self._generate_tp_compare(code_sink)
1447
1491
if self.slots.get("tp_richcompare", "NULL") == "NULL":
1448
1492
self.slots["tp_richcompare"] = self._generate_tp_richcompare(code_sink)
1494
if self.binary_numeric_operators:
1495
self.slots["tp_as_number"] = self._generate_number_methods(code_sink)
1450
1497
self._generate_type_structure(code_sink, docstring)
1499
def _generate_number_methods(self, code_sink):
1500
number_methods_var_name = "%s__py_number_methods" % (self.mangled_full_name,)
1502
pynumbermethods = PyNumberMethods()
1503
pynumbermethods.slots['variable'] = number_methods_var_name
1505
# iterate over all types and request generation of the
1506
# convertion functions for that type (so that those functions
1507
# are not generated in the middle of one of the wrappers we
1508
# are about to generate)
1509
root_module = self.module.get_root()
1510
for dummy_op_symbol, op_types in self.binary_numeric_operators.iteritems():
1511
for (retval, left, right) in op_types:
1512
root_module.generate_c_to_python_type_converter(retval.ThisClassReturn(retval.full_name), code_sink)
1513
root_module.generate_python_to_c_type_converter(left.ThisClassReturn(left.full_name), code_sink)
1514
root_module.generate_python_to_c_type_converter(right.ThisClassReturn(right.full_name), code_sink)
1516
def try_wrap_operator(op_symbol, slot_name):
1518
op_types = self.binary_numeric_operators[op_symbol]
1521
wrapper_name = "%s__%s" % (self.mangled_full_name, slot_name)
1522
pynumbermethods.slots[slot_name] = wrapper_name
1523
code_sink.writeln(("static PyObject*\n"
1524
"%s (PyObject *py_left, PyObject *py_right)\n"
1525
"{") % wrapper_name)
1527
for (retval, left, right) in op_types:
1528
retval_converter = root_module.generate_c_to_python_type_converter(retval.ThisClassReturn(retval.full_name), code_sink)
1529
left_converter = root_module.generate_python_to_c_type_converter(left.ThisClassReturn(left.full_name), code_sink)
1530
right_converter = root_module.generate_python_to_c_type_converter(right.ThisClassReturn(right.full_name), code_sink)
1532
code_sink.writeln("{")
1535
code_sink.writeln("%s left;" % left.full_name)
1536
code_sink.writeln("%s right;" % right.full_name)
1538
code_sink.writeln("if (%s(py_left, &left) && %s(py_right, &right)) {" % (left_converter, right_converter))
1540
code_sink.writeln("%s result = (left %s right);" % (retval.full_name, op_symbol))
1541
code_sink.writeln("return %s(&result);" % retval_converter)
1542
code_sink.unindent()
1543
code_sink.writeln("}")
1544
code_sink.writeln("PyErr_Clear();")
1546
code_sink.unindent()
1547
code_sink.writeln("}")
1549
code_sink.writeln("Py_INCREF(Py_NotImplemented);")
1550
code_sink.writeln("return Py_NotImplemented;")
1551
code_sink.unindent()
1552
code_sink.writeln("}")
1554
try_wrap_operator('+', 'nb_add')
1555
try_wrap_operator('-', 'nb_subtract')
1556
try_wrap_operator('*', 'nb_multiply')
1557
try_wrap_operator('/', 'nb_divide')
1559
pynumbermethods.generate(code_sink)
1560
return '&' + number_methods_var_name
1452
1562
def _generate_type_structure(self, code_sink, docstring):
1453
1563
"""generate the type structure"""
1454
1564
self.slots.setdefault("tp_basicsize",
1455
1565
"sizeof(%s)" % (self.pystruct,))
1456
for slot in ["tp_getattr", "tp_setattr", "tp_compare", "tp_repr",
1457
"tp_as_number", "tp_as_sequence", "tp_as_mapping",
1458
"tp_hash", "tp_call", "tp_str", "tp_getattro", "tp_setattro",
1459
"tp_as_buffer", "tp_traverse", "tp_clear", "tp_richcompare",
1460
"tp_iter", "tp_iternext", "tp_descr_get",
1461
"tp_descr_set", "tp_is_gc"]:
1462
self.slots.setdefault(slot, "NULL")
1464
self.slots.setdefault("tp_alloc", "PyType_GenericAlloc")
1465
self.slots.setdefault("tp_new", "PyType_GenericNew")
1466
#self.slots.setdefault("tp_free", "_PyObject_Del")
1467
self.slots.setdefault("tp_free", "0")
1468
self.slots.setdefault("tp_weaklistoffset", "0")
1566
tp_flags = set(['Py_TPFLAGS_DEFAULT'])
1469
1567
if self.allow_subclassing:
1470
self.slots.setdefault("tp_flags", ("Py_TPFLAGS_DEFAULT|"
1471
"Py_TPFLAGS_HAVE_GC|"
1472
"Py_TPFLAGS_BASETYPE"))
1568
tp_flags.add("Py_TPFLAGS_HAVE_GC")
1569
tp_flags.add("Py_TPFLAGS_BASETYPE")
1473
1570
self.slots.setdefault("tp_dictoffset",
1474
1571
"offsetof(%s, inst_dict)" % self.pystruct)
1476
self.slots.setdefault("tp_flags", "Py_TPFLAGS_DEFAULT")
1477
1573
self.slots.setdefault("tp_dictoffset", "0")
1574
if self.binary_numeric_operators:
1575
tp_flags.add("Py_TPFLAGS_CHECKTYPES")
1576
self.slots.setdefault("tp_flags", '|'.join(tp_flags))
1478
1577
self.slots.setdefault("tp_doc", (docstring is None and 'NULL'
1479
1578
or "\"%s\"" % (docstring,)))
1480
1579
dict_ = self.slots
1534
1641
or constructor))
1535
1642
return have_constructor
1644
def _generate_copy_method(self, code_sink):
1645
construct_name = self.get_construct_name()
1646
copy_wrapper_name = '_wrap_%s__copy__' % self.pystruct
1647
code_sink.writeln('''
1648
static PyObject*\n%s(%s *self)
1650
''' % (copy_wrapper_name, self.pystruct))
1653
declarations = DeclarationsScope()
1654
code_block = CodeBlock("return NULL;", declarations)
1656
if self.allow_subclassing:
1657
new_func = 'PyObject_GC_New'
1659
new_func = 'PyObject_New'
1661
py_copy = declarations.declare_variable("%s*" % self.pystruct, "py_copy")
1662
code_block.write_code("%s = %s(%s, %s);" %
1663
(py_copy, new_func, self.pystruct, '&'+self.pytypestruct))
1664
code_block.write_code("%s->obj = new %s(*self->obj);" % (py_copy, construct_name))
1665
if self.allow_subclassing:
1666
code_block.write_code("%s->inst_dict = NULL;" % py_copy)
1668
self.wrapper_registry.write_register_new_wrapper(code_block, py_copy, "%s->obj" % py_copy)
1670
code_block.write_code("return (PyObject*) %s;" % py_copy)
1672
declarations.get_code_sink().flush_to(code_sink)
1674
code_block.write_cleanup()
1675
code_block.sink.flush_to(code_sink)
1677
code_sink.unindent()
1678
code_sink.writeln("}")
1680
return copy_wrapper_name
1537
1682
def _generate_methods(self, code_sink, parent_caller_methods):
1538
1683
"""generate the method wrappers"""
1539
1684
method_defs = []
1544
1689
utils.call_with_error_handling(overload.generate, (code_sink,), {}, overload)
1545
1690
except utils.SkipWrapper:
1547
method_defs.append(overload.get_py_method_def(meth_name))
1692
if meth_name not in ['__call__']: # need to be converted to slots
1693
method_defs.append(overload.get_py_method_def(meth_name))
1548
1694
code_sink.writeln()
1549
1695
method_defs.extend(parent_caller_methods)
1697
if self.has_copy_constructor:
1699
copy_wrapper_name = utils.call_with_error_handling(self._generate_copy_method, (code_sink,), {}, self)
1700
except utils.SkipWrapper:
1703
method_defs.append('{(char *) "__copy__", (PyCFunction) %s, METH_NOARGS, NULL},' % copy_wrapper_name)
1550
1705
## generate the method table
1551
1706
code_sink.writeln("static PyMethodDef %s_methods[] = {" % (self.pystruct,))
1552
1707
code_sink.indent()
1635
1791
oss << *self->obj;
1636
1792
return PyString_FromString(oss.str ().c_str ());
1638
1795
''' % (tp_str_function_name, self.pystruct))
1797
def _generate_tp_hash(self, code_sink):
1798
"""generates a tp_hash function, which returns a hash of the self->obj pointer"""
1800
tp_hash_function_name = "_wrap_%s__tp_hash" % (self.pystruct,)
1801
self.slots.setdefault("tp_hash", tp_hash_function_name )
1803
code_sink.writeln('''
1808
return (long) self->obj;
1811
''' % (tp_hash_function_name, self.pystruct))
1813
def _generate_tp_compare(self, code_sink):
1814
"""generates a tp_compare function, which compares the ->obj pointers"""
1816
tp_compare_function_name = "_wrap_%s__tp_compare" % (self.pystruct,)
1817
self.slots.setdefault("tp_compare", tp_compare_function_name )
1819
code_sink.writeln('''
1822
%s(%s *self, %s *other)
1824
if (self->obj == other->obj) return 0;
1825
if (self->obj > other->obj) return -1;
1829
''' % (tp_compare_function_name, self.pystruct, self.pystruct))
1642
1832
def _generate_destructor(self, code_sink, have_constructor):
1643
1833
"""Generate a tp_dealloc function and register it in the type"""
1649
1839
tp_dealloc_function_name = "_wrap_%s__tp_dealloc" % (self.pystruct,)
1840
code_sink.writeln(r'''
1843
{''' % (tp_dealloc_function_name, self.pystruct))
1846
code_block = CodeBlock("PyErr_Print(); return;", DeclarationsScope())
1848
self.wrapper_registry.write_unregister_wrapper(code_block, 'self', 'self->obj')
1651
1850
if self.allow_subclassing:
1652
clear_code = "%s(self);" % self.slots["tp_clear"]
1851
code_block.write_code("%s(self);" % self.slots["tp_clear"])
1656
delete_code = self._get_delete_code()
1658
if have_constructor:
1659
code_sink.writeln(r'''
1665
self->ob_type->tp_free((PyObject*)self);
1667
''' % (tp_dealloc_function_name, self.pystruct,
1668
delete_code, clear_code))
1670
else: # don't have constructor
1672
code_sink.writeln('''
1678
self->ob_type->tp_free((PyObject*)self);
1680
''' % (tp_dealloc_function_name, self.pystruct,
1681
clear_code, delete_code))
1853
code_block.write_code(self._get_delete_code())
1855
code_block.write_code('self->ob_type->tp_free((PyObject*)self);')
1857
code_block.write_cleanup()
1859
code_block.declarations.get_code_sink().flush_to(code_sink)
1860
code_block.sink.flush_to(code_sink)
1862
code_sink.unindent()
1863
code_sink.writeln('}\n')
1683
1865
self.slots.setdefault("tp_dealloc", tp_dealloc_function_name )
1686
1868
def _generate_tp_richcompare(self, code_sink):
1687
1869
tp_richcompare_function_name = "_wrap_%s__tp_richcompare" % (self.pystruct,)
1689
code_sink.writeln("static PyObject*\n%s (%s *self, PyObject *o2, int opid)"
1690
% (tp_richcompare_function_name, self.pystruct))
1871
code_sink.writeln("static PyObject*\n%s (%s *self, %s *other, int opid)"
1872
% (tp_richcompare_function_name, self.pystruct, self.pystruct))
1691
1873
code_sink.writeln("{")
1692
1874
code_sink.indent()
1695
code_sink.writeln('PyErr_SetString(PyExc_TypeError, "Comparison not defined or not yet implemented.");')
1696
code_sink.writeln('return NULL;')
1698
#code_sink.writeln("Py_INCREF(Py_NotImplemented);")
1699
#code_sink.writeln("return Py_NotImplemented;")
1876
code_sink.writeln("""
1877
if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &%s)) {
1878
Py_INCREF(Py_NotImplemented);
1879
return Py_NotImplemented;
1880
}""" % self.pytypestruct)
1882
code_sink.writeln("switch (opid)\n{")
1884
def wrap_operator(name, opid_code):
1885
code_sink.writeln("case %s:" % opid_code)
1887
if name in self.binary_comparison_operators:
1888
code_sink.writeln("if (*self->obj %(OP)s *other->obj) {\n"
1889
" Py_INCREF(Py_True);\n"
1890
" return Py_True;\n"
1892
" Py_INCREF(Py_False);\n"
1893
" return Py_False;\n"
1894
"}" % dict(OP=name))
1896
code_sink.writeln("Py_INCREF(Py_NotImplemented);\n"
1897
"return Py_NotImplemented;")
1898
code_sink.unindent()
1900
wrap_operator('<', 'Py_LT')
1901
wrap_operator('<=', 'Py_LE')
1902
wrap_operator('==', 'Py_EQ')
1903
wrap_operator('!=', 'Py_NE')
1904
wrap_operator('>=', 'Py_GE')
1905
wrap_operator('>', 'Py_GT')
1907
code_sink.writeln("} /* closes switch (opid) */")
1909
code_sink.writeln("Py_INCREF(Py_NotImplemented);\n"
1910
"return Py_NotImplemented;")
1701
1912
code_sink.unindent()
1702
1913
code_sink.writeln("}\n")