diff --git a/CMakeLists.txt b/CMakeLists.txt index e4a946c9c..69be3d8d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ string(REGEX REPLACE "([a-zA-Z_]+)\\.po" "\\1" LINPHONE_ALL_LANGS_LIST "${LINPHO string(REPLACE ";" " " LINPHONE_ALL_LANGS "${LINPHONE_ALL_LANGS_LIST}") include(CMakeDependentOption) +include(cmake/Tools.cmake) option(ENABLE_SHARED "Build shared library." YES) option(ENABLE_STATIC "Build static library." YES) @@ -46,8 +47,7 @@ option(ENABLE_CXX_WRAPPER "Build the C++ wrapper for Liblinphone." YES) option(ENABLE_DAEMON "Enable the linphone daemon interface." YES) option(ENABLE_DATE "Use build date in internal version number." NO) option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO) -option(ENABLE_DOC "Enable documentation generation with Doxygen." YES) -option(ENABLE_SPHINX_DOC "Enable sphinx documentation generation." NO) +option(ENABLE_DOC "Enable API documentation generation." NO) option(ENABLE_JAVADOC "Add a target to generate documentation for Java API" NO) option(ENABLE_LDAP "Enable LDAP support." NO) option(ENABLE_RELATIVE_PREFIX "Find resources relatively to the installation directory." NO) @@ -173,8 +173,15 @@ if(ENABLE_LIME) endif() set(HAVE_LIME 1) endif() -if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER OR ENABLE_SPHINX_DOC) +if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER OR ENABLE_DOC) find_package(PythonInterp REQUIRED) + check_python_module(pystache) + check_python_module(six) + if(ENABLE_DOC) + check_python_module(sphinx) + check_python_module(javasphinx) + check_python_module(sphinx_csharp) + endif() endif() if(UNIX AND NOT APPLE) diff --git a/README.md b/README.md index f9eb8a190..3935415a6 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,22 @@ Building liblinphone ### Required dependencies -* *BcToolbox[2]*: portability layer -* *BelleSIP[3]*: SIP stack -* *Mediastreamer2[4]*: multimedia engine -* *Belcard[5]*: VCard support -* libxml2 -* zlib -* libsqlite3: user data storage (disablable) -* gettext and libintl: internationalization support (disablable) +* **BcToolbox[2]:** portability layer +* **BelleSIP[3]:** SIP stack +* **Mediastreamer2[4]:** multimedia engine +* **Belcard[5]:** VCard support +* **libxml2** +* **zlib** +* **libsqlite3:** user data storage (disablable) +* **gettext** and **libintl**: internationalization support (disablable) +* **python interpreter** and **pystache**, **six** python module (needed for C++ wrapper and API documentaiton) +* **doxygen** and **dot** (needed for C++ wrapper and API documentation) ### Opitonal dependencies -* *Bzrtp[6]*: zrtp stack used for Linphone Instant Messaging Encryption +* **Bzrtp[6]**: zrtp stack used for Linphone Instant Messaging Encryption. +* For API documentatino generation: **sphinx**, **javasphinx**, **sphinx_csharp** python modules are needed. ### Build instructions @@ -36,17 +39,17 @@ Building liblinphone ### Supported build opitons -* `CMAKE_INSTALL_PREFIX=` : install prefix -* `CMAKE_PREFIX_PATH=` : column-separated list of prefixes where to search for dependencies -* `ENABLE_SHARED=NO` : do not build the shared library -* `ENABLE_STATIC=NO` : do not build the static library -* `ENABLE_STRICT=NO` : build without strict compilation flags (-Wall -Werror) -* `ENABLE_DOC=NO` : do not generate the reference documentation of liblinphone -* `ENABLE_UNIT_TESTS=NO` : do not build testing binaries -* `ENABLE_VCARD=NO` : disable VCard support -* `ENABLE_SQLITE_STORAGE=NO` : disable SQlite user data storage (message, history, contacts list) -* `ENABLE_TOOLS=NO` : do not build tool binaries -* `ENABLE_LIME=YES` : disable Linphone Instant Messaging Encryption +* **`CMAKE_INSTALL_PREFIX=`** : install prefix +* **`CMAKE_PREFIX_PATH=`** : column-separated list of prefixes where to search for dependencies +* **`ENABLE_SHARED=NO`** : do not build the shared library +* **`ENABLE_STATIC=NO`** : do not build the static library +* **`ENABLE_STRICT=NO`** : build without strict compilation flags (-Wall -Werror) +* **`ENABLE_DOC=YES`** : Make the reference documentation of liblinphone to generated +* **`ENABLE_UNIT_TESTS=NO`** : do not build testing binaries +* **`ENABLE_VCARD=NO`** : disable VCard support +* **`ENABLE_SQLITE_STORAGE=NO`** : disable SQlite user data storage (message, history, contacts list) +* **`ENABLE_TOOLS=NO`** : do not build tool binaries +* **`ENABLE_LIME=YES`** : disable Linphone Instant Messaging Encryption ### Note for packagers @@ -89,4 +92,4 @@ Here is a short description of the content of the source tree. - [3] belle-sip: git://git.linphone.org/belle-sip.git *or* - [4] mediastreamer2: git://git.linphone.org/mediastreamer2.git *or* - [5] belcard: git://git.linphone.org/belcard.git *or* -- [5] bzrtp: git://git.linphone.org/bzrtp.git *or* +- [6] bzrtp: git://git.linphone.org/bzrtp.git *or* diff --git a/cmake/Tools.cmake b/cmake/Tools.cmake new file mode 100644 index 000000000..8c3d3d0c7 --- /dev/null +++ b/cmake/Tools.cmake @@ -0,0 +1,33 @@ +############################################################################ +# LinphoneUtils.cmake +# Copyright (C) 2018 Belledonne Communications, Grenoble France +# +############################################################################ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################ + +function(check_python_module module_name) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import ${module_name}" + RESULT_VARIABLE result + OUTPUT_QUIET + ERROR_QUIET) + if(result EQUAL 0) + message(STATUS "'${module_name}' python module found") + else() + message(FATAL_ERROR "'${module_name}' python module not found") + endif() +endfunction() diff --git a/coreapi/help/doc/doxygen/CMakeLists.txt b/coreapi/help/doc/doxygen/CMakeLists.txt index f1609051b..57dd6b574 100644 --- a/coreapi/help/doc/doxygen/CMakeLists.txt +++ b/coreapi/help/doc/doxygen/CMakeLists.txt @@ -31,11 +31,6 @@ if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRA endforeach () string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${CMAKE_CURRENT_SOURCE_DIR}\"") string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${PROJECT_SOURCE_DIR}/coreapi/help/examples/C\"") - if(ENABLE_DOC) - set(GENERATE_HTML "YES") - else() - set(GENERATE_HTML "NO") - endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) set(DOC_INPUT_FILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.dox @@ -43,16 +38,12 @@ if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRA ) set(XML_DIR "${CMAKE_CURRENT_BINARY_DIR}/xml") set(LINPHONE_DOXYGEN_XML_DIR ${XML_DIR} PARENT_SCOPE) - add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml" - COMMAND ${CMAKE_COMMAND} -E remove -f html/* xml/* + add_custom_command(OUTPUT "${XML_DIR}/index.xml" + COMMAND ${CMAKE_COMMAND} -E remove -f xml/* COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile DEPENDS ${DOC_INPUT_FILES} ) - add_custom_target(linphone-doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml") - if(ENABLE_DOC) - install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html" "${XML_DIR}" - DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/linphone-${LINPHONE_VERSION}") - endif() + add_custom_target(linphone-doc ALL DEPENDS "${XML_DIR}/index.xml") else() if (ENABLE_CXX_WRAPPER) message(FATAL_ERROR "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.") diff --git a/coreapi/help/doc/doxygen/Doxyfile.in b/coreapi/help/doc/doxygen/Doxyfile.in index 6f6724101..651017491 100644 --- a/coreapi/help/doc/doxygen/Doxyfile.in +++ b/coreapi/help/doc/doxygen/Doxyfile.in @@ -1045,7 +1045,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = ${GENERATE_HTML} +GENERATE_HTML = NO # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of diff --git a/coreapi/help/doc/sphinx/CMakeLists.txt b/coreapi/help/doc/sphinx/CMakeLists.txt index 92699653a..5b1593126 100644 --- a/coreapi/help/doc/sphinx/CMakeLists.txt +++ b/coreapi/help/doc/sphinx/CMakeLists.txt @@ -20,7 +20,7 @@ # ############################################################################ -if (ENABLE_SPHINX_DOC) +if (ENABLE_DOC) set(doc_source_dir ${CMAKE_CURRENT_BINARY_DIR}/source) set(doc_output_dir ${CMAKE_CURRENT_BINARY_DIR}/build) set(reference_doc_source_dir ${doc_source_dir}/reference) @@ -43,7 +43,6 @@ if (ENABLE_SPHINX_DOC) index.rst logo.png samples/samples.rst - toc.rst ) configure_file(conf.py.in ${doc_source_dir}/conf.py) foreach(file ${static_documentation_files}) diff --git a/coreapi/help/doc/sphinx/gendoc.py b/coreapi/help/doc/sphinx/gendoc.py index 252f68d09..514dfb596 100755 --- a/coreapi/help/doc/sphinx/gendoc.py +++ b/coreapi/help/doc/sphinx/gendoc.py @@ -68,12 +68,27 @@ class RstTools: class Table: def __init__(self): self._rows = [] - self._widths = [] - self._heights = [] - + @property def rows(self): return self._rows + + class CSVTable(Table): + def addrow(self, row): + self._rows.append(', '.join([self._format_cell(cell) for cell in row])) + + def __str__(self): + return '.. csv-table::\n\t\n\t' + '\n\t'.join(self._rows) + + def _format_cell(self, cell): + return '"{0}"'.format(cell.replace('"', '""')) + + + class GridTable(Table): + def __init__(self): + RstTools.Table.__init__(self) + self._widths = [] + self._heights = [] def addrow(self, row): if len(self._widths) == 0: @@ -315,7 +330,7 @@ class ClassPage(SphinxPage): self.briefDoc = _class.briefDescription.translate(self.docTranslator) self.detailedDoc = _class.detailedDescription.translate(self.docTranslator) if _class.detailedDescription is not None else None self.enums = [EnumPart(enum, lang, langs) for enum in _class.enums] - self.properties = self._translate_properties(_class.properties) + self.properties = self._translate_properties(_class.properties) if isinstance(_class, abstractapi.Class) else [] self.methods = self._translate_methods(_class.instanceMethods) self.classMethods = self._translate_methods(_class.classMethods) self.selector = self._make_selector(_class) @@ -361,7 +376,7 @@ class ClassPage(SphinxPage): return translatedMethods def _translate_method(self, method): - namespace = method.find_first_ancestor_by_type(abstractapi.Class) + namespace = method.find_first_ancestor_by_type(abstractapi.Class,abstractapi.Interface) methAttr = { 'prototype' : method.translate_as_prototype(self.lang.langTranslator, namespace=namespace), 'briefDoc' : method.briefDescription.translate(self.docTranslator), @@ -375,35 +390,35 @@ class ClassPage(SphinxPage): @property def enumsSummary(self): - table = RstTools.Table() + table = RstTools.CSVTable() for enum in self.enums: - briefDoc = '\n'.join([line['line'] for line in enum.briefDesc['lines']]) + briefDoc = ' '.join([line['line'] for line in enum.briefDesc['lines']]) table.addrow((enum.link, briefDoc)) return table @property def propertiesSummary(self): - table = RstTools.Table() + table = RstTools.CSVTable() for property_ in self.properties: reference = ':ref:`{0}`'.format(property_['ref_label']) briefDoc = property_['getter']['briefDoc'] if property_['getter'] is not None else property_['setter']['briefDoc'] - briefDoc = '\n'.join([line['line'] for line in briefDoc['lines']]) + briefDoc = ' '.join([line['line'] for line in briefDoc['lines']]) table.addrow([reference, briefDoc]) return table @property def instanceMethodsSummary(self): - table = RstTools.Table() + table = RstTools.CSVTable() for method in self.methods: - briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']]) + briefDoc = ' '.join([line['line'] for line in method['briefDoc']['lines']]) table.addrow([method['link'], briefDoc]) return table @property def classMethodsSummary(self): - table = RstTools.Table() + table = RstTools.CSVTable() for method in self.classMethods: - briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']]) + briefDoc = ' '.join([line['line'] for line in method['briefDoc']['lines']]) table.addrow([method['link'], briefDoc]) return table @@ -413,7 +428,7 @@ class OldFilesCleaner: self._filesToKeep = set() self.root = rootDirectory - def add_directory(self, directory): + def protect_file(self, directory): self._filesToKeep.add(directory) def clean(self): @@ -448,14 +463,14 @@ class DocGenerator: page = EnumPage(enum, lang, self.languages) filepath = page.write(directory) indexPage.add_entry(page.filename) - cleaner.add_directory(filepath) - for class_ in self.api.namespace.classes: + cleaner.protect_file(filepath) + for class_ in (self.api.namespace.classes + self.api.namespace.interfaces): page = ClassPage(class_, lang, self.languages) filepath = page.write(directory) indexPage.add_entry(page.filename) - cleaner.add_directory(filepath) + cleaner.protect_file(filepath) filepath = indexPage.write(directory) - cleaner.add_directory(filepath) + cleaner.protect_file(filepath) cleaner.clean() diff --git a/include/linphone/proxy_config.h b/include/linphone/proxy_config.h index 3bdd9df4b..5242a71e1 100644 --- a/include/linphone/proxy_config.h +++ b/include/linphone/proxy_config.h @@ -117,8 +117,9 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, #define linphone_proxy_config_expires linphone_proxy_config_set_expires /** - * Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig . - *
In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule. + * @brief Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig . + * + * In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule. * @param[in] cfg #LinphoneProxyConfig object. * @param val if true, registration will be engaged */ diff --git a/tools/abstractapi.py b/tools/abstractapi.py index a13dd241d..e4a464b43 100644 --- a/tools/abstractapi.py +++ b/tools/abstractapi.py @@ -428,27 +428,32 @@ class Class(Namespace): self.classMethods.sort() -class Interface(DocumentableObject): +class Interface(Namespace): def __init__(self, name): - DocumentableObject.__init__(self, name) - self.methods = [] + Namespace.__init__(self, name) + self.instanceMethods = [] + self.classMethods = [] self._listenedClass = None - - def add_method(self, method): - self.methods.append(method) + + def add_instance_methods(self, method): + self.instanceMethods.append(method) method.parent = self - + + def add_class_methods(self, method): + self.classMethods.append(method) + method.parent = self + @property def listenedClass(self): return self._listenedClass - + @listenedClass.setter def listenedClass(self, method): - self.methods.append(method) + self.instanceMethods.append(method) method.parent = self - + def sort(self): - self.methods.sort() + self.instanceMethods.sort() class CParser(object): @@ -619,7 +624,7 @@ class CParser(object): self._fix_all_types_in_method(method) def _fix_all_types_in_interface(self, interface): - for method in interface.methods: + for method in interface.instanceMethods: self._fix_all_types_in_method(method) def _fix_all_types_in_method(self, method): @@ -784,7 +789,7 @@ class CParser(object): if property.name != 'user_data': try: method = self._parse_listener_property(property, listener, cclass.events) - listener.add_method(method) + listener.add_instance_methods(method) except BlacklistedSymbolError as e: logger.debug(e) @@ -819,6 +824,8 @@ class CParser(object): argName.from_snake_case(arg.name) argument = Argument(argName, self.parse_type(arg)) method.add_arguments(argument) + method.briefDescription = event.briefDoc + method.detailedDescription = event.detailedDoc return method @@ -1005,7 +1012,7 @@ class CLangTranslator(CLikeLangTranslator): raise TypeError('invalid enumerator value type: {0}'.format(value)) def translate_method_as_prototype(self, method, hideArguments=False, hideArgNames=False, hideReturnType=False, stripDeclarators=False, namespace=None): - _class = method.find_first_ancestor_by_type(Class) + _class = method.find_first_ancestor_by_type(Class,Interface) params = [] if not hideArguments: params.append('{const}{className} *obj'.format( diff --git a/tools/genapixml.py b/tools/genapixml.py index e7530d412..e3f699cff 100755 --- a/tools/genapixml.py +++ b/tools/genapixml.py @@ -460,6 +460,8 @@ class Project: definition = node.find('./definition').text if definition.startswith('typedef '): definition = definition[8 :] + briefDoc = self.docparser.parse_description(node.find('./briefdescription')) + detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) if name.endswith('Cb'): pos = definition.find("(*") if pos == -1: @@ -515,9 +517,9 @@ class Project: if deprecatedNode is not None: f.deprecated = True f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() - f.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) - f.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) + f.briefDoc = briefDoc f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + f.detailedDoc = detailedDoc return f else: pos = definition.rfind(" " + name) @@ -528,9 +530,9 @@ class Project: if deprecatedNode is not None: td.deprecated = True td.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip() - td.briefDoc = self.docparser.parse_description(node.find('./briefdescription')) - td.detailedDoc = self.docparser.parse_description(node.find('./detaileddescription')) + td.briefDoc = briefDoc td.detailedDescription = self.__cleanDescription(node.find('./detaileddescription')) + td.detailedDoc = detailedDoc return td return None diff --git a/tools/metadoc.py b/tools/metadoc.py index df3c8ee01..1e4967e08 100644 --- a/tools/metadoc.py +++ b/tools/metadoc.py @@ -558,6 +558,7 @@ class SphinxTranslator(Translator): if langCode == 'C': self.domain = 'cpp' self.classDeclarator = 'type' + self.interfaceDeclarator = self.classDeclarator self.methodDeclarator = 'function' self.enumDeclarator = 'enum' self.enumeratorDeclarator = 'enumerator' @@ -565,6 +566,7 @@ class SphinxTranslator(Translator): elif langCode == 'Cpp': self.domain = 'cpp' self.classDeclarator = 'class' + self.interfaceDeclarator = self.classDeclarator self.methodDeclarator = 'function' self.enumDeclarator = 'enum' self.enumeratorDeclarator = 'enumerator' @@ -573,17 +575,20 @@ class SphinxTranslator(Translator): elif langCode == 'CSharp': self.domain = 'csharp' self.classDeclarator = 'class' + self.interfaceDeclarator = self.classDeclarator self.methodDeclarator = 'method' self.enumDeclarator = 'enum' self.enumeratorDeclarator = 'value' self.namespaceDeclarator = 'namespace' self.classReferencer = 'type' + self.interfaceReferencer = self.classReferencer self.enumReferencer = 'type' self.enumeratorReferencer = 'enum' self.methodReferencer = 'meth' elif langCode == 'Java': self.domain = 'java' self.classDeclarator = 'type' + self.interfaceDeclarator = self.classDeclarator self.methodDeclarator = 'method' self.enumDeclarator = 'type' self.enumeratorDeclarator = 'field' diff --git a/wrappers/cpp/genwrapper.py b/wrappers/cpp/genwrapper.py index 6ac3908f6..c67edb99a 100755 --- a/wrappers/cpp/genwrapper.py +++ b/wrappers/cpp/genwrapper.py @@ -104,7 +104,7 @@ class CppTranslator(object): classDict['listenerClassName'] = _class.listenerInterface.name.translate(self.nameTranslator) classDict['cListenerName'] = _class.listenerInterface.name.to_c() classDict['cppListenerName'] = _class.listenerInterface.name.translate(self.nameTranslator) - for method in _class.listenerInterface.methods: + for method in _class.listenerInterface.instanceMethods: classDict['wrapperCbs'].append(self._generate_wrapper_callback(_class, method)) if ismonolistenable: @@ -173,7 +173,7 @@ class CppTranslator(object): 'isListener' : True, 'methods' : [] } - for method in interface.methods: + for method in interface.instanceMethods: methodDict = self.translate_method(method, genImpl=False) intDict['methods'].append(methodDict) @@ -375,7 +375,7 @@ class ClassHeader(object): if type(_class) is AbsApi.Class: methods = _class.classMethods + _class.instanceMethods else: - methods = _class.methods + methods = _class.instanceMethods for method in methods: self._populate_needed_includes_from_type(method.returnType) diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py index a123d2c50..1572e2381 100755 --- a/wrappers/java/genwrapper.py +++ b/wrappers/java/genwrapper.py @@ -465,7 +465,7 @@ class JavaTranslator(object): interfaceDict['doc'] = _class.briefDescription.translate(self.docTranslator) - for method in _class.methods: + for method in _class.instanceMethods: interfaceDict['methods'].append(self.translate_method(method)) interfaceDict['jniMethods'].append(self.translate_jni_interface(_class.listenedClass, _class.name, method)) @@ -528,7 +528,7 @@ class JniInterface(object): self.cPrefix = javaClass.cPrefix self.callbacks = [] listener = apiClass.listenerInterface - for method in listener.methods: + for method in listener.instanceMethods: self.callbacks.append({ 'callbackName': '_{0}_cb'.format(method.name.to_snake_case(fullName=True)), 'callback': method.name.to_snake_case()[3:], # Remove the on_