diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py index d6746ad08..2c32a24f6 100755 --- a/tools/python/apixml2python.py +++ b/tools/python/apixml2python.py @@ -71,13 +71,13 @@ blacklisted_functions = [ 'lp_config_section_to_dict' # missing LinphoneDictionary ] hand_written_functions = [ - HandWrittenClassMethod('Buffer', 'new_from_data', 'linphone_buffer_new_from_data'), - HandWrittenProperty('Buffer', 'content', 'linphone_buffer_get_content', 'linphone_buffer_set_content'), - HandWrittenProperty('Content', 'buffer', 'linphone_content_get_buffer', 'linphone_content_set_buffer'), - HandWrittenProperty('Core', 'sound_devices', 'linphone_core_get_sound_devices', None), - HandWrittenProperty('Core', 'video_devices', 'linphone_core_get_video_devices', None), - HandWrittenClassMethod('Core', 'new', 'linphone_core_new'), - HandWrittenClassMethod('Core', 'new_with_config', 'linphone_core_new_with_config') + HandWrittenClassMethod('Buffer', 'new_from_data', 'linphone_buffer_new_from_data', "Create a new LinphoneBuffer object from existing data.\n\n:param data: The initial data to store in the LinphoneBuffer.\n:type data: ByteArray\n:returns: A new LinphoneBuffer object.\n:rtype: linphone.Buffer"), + HandWrittenProperty('Buffer', 'content', 'linphone_buffer_get_content', 'linphone_buffer_set_content', "[ByteArray] Set the content of the data buffer."), + HandWrittenProperty('Content', 'buffer', 'linphone_content_get_buffer', 'linphone_content_set_buffer', "[ByteArray] Set the content data buffer."), + HandWrittenProperty('Core', 'sound_devices', 'linphone_core_get_sound_devices', None, "[list of string] Get the available sound devices."), + HandWrittenProperty('Core', 'video_devices', 'linphone_core_get_video_devices', None, "[list of string] Get the available video capture devices."), + HandWrittenClassMethod('Core', 'new', 'linphone_core_new', "Instantiate a LinphoneCore object.\n\n:param vtable: The callbacks.\n:type vtable: dictionary\n:param configPath: A path to a config file. If it does not exists it will be created. The config file is used to store all settings, call logs, friends, proxies... so that all these settings become persistent over the life of the LinphoneCore object. It is allowed to set to None. In that case LinphoneCore will not store any settings.\n:type configPath: string\n:param factoryConfigPath: A path to a read-only config file that can be used to store hard-coded preference such as proxy settings or internal preferences. The settings in this factory file always override the one in the normal config file. It is OPTIONAL, use None if unneeded.\n:type factoryConfigPath: string\n:rtype: linphone.Core"), + HandWrittenClassMethod('Core', 'new_with_config', 'linphone_core_new_with_config', "Instantiate a LinphoneCore object from a LpConfig.\n\n:param vtable: The callbacks.\n:type vtable: dictionary\n:param config: A LpConfig object holding the configuration of the LinphoneCore to be instantiated.\n:rtype: linphone.Core") ] def generate(apixmlfile, outputfile): diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py index ce333a475..c1d37858d 100644 --- a/tools/python/apixml2python/linphone.py +++ b/tools/python/apixml2python/linphone.py @@ -15,6 +15,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +import re from sets import Set import sys @@ -25,6 +26,18 @@ def strip_leading_linphone(s): else: return s +def remove_useless_enum_prefix(senum, svalue): + lenum = re.findall('[A-Z][^A-Z]*', senum) + lvalue = re.findall('[A-Z][^A-Z]*', svalue) + if len(lenum) == 0 or len(lvalue) == 0: + return svalue + if lenum[0] == lvalue[0]: + i = 0 + while i < len(lenum) and lenum[i] == lvalue[i]: + i += 1 + return ''.join(lvalue[i:]) + return svalue + def is_callback(s): return s.startswith('Linphone') and s.endswith('Cb') @@ -42,27 +55,28 @@ def compute_event_name(s, className): class HandWrittenCode: - def __init__(self, _class, name, func_list): + def __init__(self, _class, name, func_list, doc = ''): self._class = _class self.name = name self.func_list = func_list + self.doc = doc class HandWrittenInstanceMethod(HandWrittenCode): - def __init__(self, _class, name, cfunction): - HandWrittenCode.__init__(self, _class, name, [cfunction]) + def __init__(self, _class, name, cfunction, doc = ''): + HandWrittenCode.__init__(self, _class, name, [cfunction], doc) class HandWrittenClassMethod(HandWrittenCode): - def __init__(self, _class, name, cfunction): - HandWrittenCode.__init__(self, _class, name, [cfunction]) + def __init__(self, _class, name, cfunction, doc = ''): + HandWrittenCode.__init__(self, _class, name, [cfunction], doc) class HandWrittenProperty(HandWrittenCode): - def __init__(self, _class, name, getter_cfunction = None, setter_cfunction = None): + def __init__(self, _class, name, getter_cfunction = None, setter_cfunction = None, doc = ''): func_list = [] if getter_cfunction is not None: func_list.append(getter_cfunction) if setter_cfunction is not None: func_list.append(setter_cfunction) - HandWrittenCode.__init__(self, _class, name, func_list) + HandWrittenCode.__init__(self, _class, name, func_list, doc) self.getter_cfunction = getter_cfunction self.setter_cfunction = setter_cfunction @@ -947,18 +961,35 @@ class LinphoneModule(object): e = {} e['enum_name'] = strip_leading_linphone(xml_enum.get('name')) e['enum_doc'] = self.__format_doc_content(xml_enum.find('briefdescription'), xml_enum.find('detaileddescription')) - e['enum_doc'] += "\n\nValues:\n" + e['enum_doc'] = self.__replace_doc_special_chars(e['enum_doc']) + e['enum_doc'] += """ + +.. csv-table:: + :delim: | + :widths: 30, 70 + :header: Value,Description + +""" e['enum_values'] = [] + e['enum_deprecated_values'] = [] xml_enum_values = xml_enum.findall("./values/value") for xml_enum_value in xml_enum_values: if xml_enum_value.get('deprecated') == 'true': continue v = {} v['enum_value_cname'] = xml_enum_value.get('name') - v['enum_value_name'] = strip_leading_linphone(v['enum_value_cname']) + valname = strip_leading_linphone(v['enum_value_cname']) + v['enum_value_name'] = remove_useless_enum_prefix(e['enum_name'], valname) v['enum_value_doc'] = self.__format_doc(xml_enum_value.find('briefdescription'), xml_enum_value.find('detaileddescription')) - e['enum_doc'] += '\t' + v['enum_value_name'] + ': ' + v['enum_value_doc'] + '\n' + e['enum_doc'] += ' ' + v['enum_value_name'] + '|' + v['enum_value_doc'] + '\n' e['enum_values'].append(v) + if v['enum_value_name'] != valname: + # TODO: To remove. Add deprecated value name. + v = {} + v['enum_value_cname'] = xml_enum_value.get('name') + v['enum_value_name'] = strip_leading_linphone(v['enum_value_cname']) + v['enum_value_doc'] = self.__format_doc(xml_enum_value.find('briefdescription'), xml_enum_value.find('detaileddescription')) + e['enum_deprecated_values'].append(v) e['enum_doc'] = self.__replace_doc_special_chars(e['enum_doc']) self.enums.append(e) self.enum_names.append(e['enum_name']) @@ -1012,10 +1043,12 @@ class LinphoneModule(object): if isinstance(hand_written_code, HandWrittenClassMethod): m = {} m['method_name'] = hand_written_code.name + m['method_doc'] = self.__replace_doc_special_chars(hand_written_code.doc) c['class_type_hand_written_methods'].append(m) elif isinstance(hand_written_code, HandWrittenInstanceMethod): m = {} m['method_name'] = hand_written_code.name + m['method_doc'] = self.__replace_doc_special_chars(hand_written_code.doc) c['class_instance_hand_written_methods'].append(m) elif isinstance(hand_written_code, HandWrittenProperty): p = {} @@ -1028,6 +1061,7 @@ class LinphoneModule(object): p['setter_reference'] = 'NULL' else: p['setter_reference'] = '(setter)pylinphone_' + c['class_name'] + '_set_' + p['property_name'] + p['property_doc'] = self.__replace_doc_special_chars(hand_written_code.doc) c['class_hand_written_properties'].append(p) xml_type_methods = xml_class.findall("./classmethods/classmethod") for xml_type_method in xml_type_methods: diff --git a/tools/python/apixml2python/linphone_module.mustache b/tools/python/apixml2python/linphone_module.mustache index e31451cfa..13e0c1c6b 100644 --- a/tools/python/apixml2python/linphone_module.mustache +++ b/tools/python/apixml2python/linphone_module.mustache @@ -148,14 +148,14 @@ static PyObject * pylinphone_{{class_name}}_instance_method_{{method_name}}(PyOb static PyMethodDef pylinphone_{{class_name}}_methods[] = { /* Class methods */ {{#class_type_hand_written_methods}} - { "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "" }, + { "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "{{{method_doc}}}" }, {{/class_type_hand_written_methods}} {{#class_type_methods}} { "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "{{{method_doc}}}" }, {{/class_type_methods}} /* Instance methods */ {{#class_instance_hand_written_methods}} - { "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "" }, + { "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "{{{method_doc}}}" }, {{/class_instance_hand_written_methods}} {{#class_instance_methods}} { "{{method_name}}", pylinphone_{{class_name}}_instance_method_{{method_name}}, METH_VARARGS, "{{{method_doc}}}" }, @@ -183,7 +183,7 @@ static PyMemberDef pylinphone_{{class_name}}_members[] = { static PyGetSetDef pylinphone_{{class_name}}_getseters[] = { {{#class_hand_written_properties}} - { "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "" }, + { "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "{{{property_doc}}}" }, {{/class_hand_written_properties}} {{#class_properties}} { "{{property_name}}", {{getter_reference}}, {{setter_reference}}, "{{{property_doc}}}" }, @@ -308,12 +308,21 @@ PyMODINIT_FUNC initlinphone(void) { {{#enum_values}} if (PyModule_AddIntConstant(menum, "{{enum_value_name}}", {{enum_value_cname}}) < 0) return; {{/enum_values}} +{{#enum_deprecated_values}} + if (PyModule_AddIntConstant(menum, "{{enum_value_name}}", {{enum_value_cname}}) < 0) return; +{{/enum_deprecated_values}} {{/enums}} - menum = Py_InitModule3("PayloadTypeType", pylinphone_PayloadTypeType_ModuleMethods, "Type of linphone.PayloadType."); + menum = Py_InitModule3("PayloadTypeType", pylinphone_PayloadTypeType_ModuleMethods, "Type of linphone.PayloadType.\n\n.. csv-table::\n :delim: |\n :header: Value,Description\n\n AudioContinuous|\n AudioPacketized|\n Video|\n Text|\n Other|\n"); if (menum == NULL) return; Py_INCREF(menum); if (PyModule_AddObject(m, "PayloadTypeType", menum) < 0) return; + if (PyModule_AddIntConstant(menum, "AudioContinuous", PAYLOAD_AUDIO_CONTINUOUS) < 0) return; + if (PyModule_AddIntConstant(menum, "AudioPacketized", PAYLOAD_AUDIO_PACKETIZED) < 0) return; + if (PyModule_AddIntConstant(menum, "Video", PAYLOAD_VIDEO) < 0) return; + if (PyModule_AddIntConstant(menum, "Text", PAYLOAD_TEXT) < 0) return; + if (PyModule_AddIntConstant(menum, "Other", PAYLOAD_OTHER) < 0) return; + // TODO: To remove. Deprecated enum values. if (PyModule_AddIntConstant(menum, "PAYLOAD_AUDIO_CONTINUOUS", PAYLOAD_AUDIO_CONTINUOUS) < 0) return; if (PyModule_AddIntConstant(menum, "PAYLOAD_AUDIO_PACKETIZED", PAYLOAD_AUDIO_PACKETIZED) < 0) return; if (PyModule_AddIntConstant(menum, "PAYLOAD_VIDEO", PAYLOAD_VIDEO) < 0) return; diff --git a/tools/python/doc/Makefile b/tools/python/doc/Makefile index b8c40c718..158616058 100644 --- a/tools/python/doc/Makefile +++ b/tools/python/doc/Makefile @@ -48,8 +48,12 @@ help: clean: rm -rf $(BUILDDIR)/* + rm -f source/enums.rst -html: +source/enums.rst: + python generate_enums.py -o source/enums.rst + +html: source/enums.rst $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/tools/python/doc/generate_enums.py b/tools/python/doc/generate_enums.py new file mode 100644 index 000000000..2f24a7a93 --- /dev/null +++ b/tools/python/doc/generate_enums.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +import argparse +import types +import sys + +def main(argv = None): + if argv is None: + argv = sys.argv + argparser = argparse.ArgumentParser(description="Generate enums documentation of the Linphone API.") + argparser.add_argument('-o', '--outputfile', metavar='outputfile', type=argparse.FileType('w'), help="Output .rst file describing the Linphone API enums.") + args = argparser.parse_args() + if args.outputfile == None: + args.outputfile = open('enums.rst', 'w') + + module = __import__('linphone', globals(), locals()) + + for name in dir(module): + if name == 'testing' or name == 'linphone': + continue + if type(getattr(module, name)) == types.ModuleType: + args.outputfile.write('linphone.' + name + '\n') + args.outputfile.write('^' * len('linphone.' + name) + '\n\n') + args.outputfile.write(getattr(module, name).__doc__) + args.outputfile.write('\n') + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/python/doc/source/_static/pylinphone.js b/tools/python/doc/source/_static/pylinphone.js new file mode 100644 index 000000000..b0b7617a0 --- /dev/null +++ b/tools/python/doc/source/_static/pylinphone.js @@ -0,0 +1,52 @@ +$(function (){ +var createList = function(selector){ + + var ul = $('