changeset 180:ddf3e987827f java-code-model

created Python documentation for the Orthanc interface
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 02 Jul 2024 12:30:16 +0200
parents f49864df6f1f
children faaa3fec799a
files CMakeLists.txt CodeAnalysis/GenerateOrthancSDK.py CodeAnalysis/PythonDocumentation.mustache NEWS
diffstat 4 files changed, 190 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Thu Jun 27 21:53:03 2024 +0200
+++ b/CMakeLists.txt	Tue Jul 02 12:30:16 2024 +0200
@@ -215,6 +215,11 @@
   SOVERSION ${PLUGIN_VERSION}
   )
 
+configure_file(
+  Sources/Autogenerated/orthanc.pyi
+  ${CMAKE_CURRENT_BINARY_DIR}/orthanc.pyi
+  COPYONLY)
+
 install(
   TARGETS OrthancPython
   RUNTIME DESTINATION lib    # Destination for Windows
--- a/CodeAnalysis/GenerateOrthancSDK.py	Thu Jun 27 21:53:03 2024 +0200
+++ b/CodeAnalysis/GenerateOrthancSDK.py	Tue Jul 02 12:30:16 2024 +0200
@@ -59,9 +59,17 @@
         'args' : [
             {
                 'name' : 'arg0',
+                'sdk_name' : 'size',
                 'sdk_type' : 'uint32_t',
             }
         ],
+        'documentation' : {
+            'args' : {
+                'size' : 'Size of the memory buffer to be created',
+            },
+            'return' : 'The newly allocated memory buffer',
+            'description' : [ 'Create a new memory buffer managed by the Orthanc core' ],
+        },
         'return_sdk_type' : 'OrthancPluginMemoryBuffer *',
     }
 ]
@@ -138,6 +146,16 @@
     return s
 
 
+def ToLowerCase(name):
+    s = ''
+    for i in range(len(name)):
+        if (name[i].isupper() and
+            len(s) != 0):
+            s += '_'
+        s += name[i].lower()
+    return s
+
+
 def GetShortName(name):
     if not name.startswith('OrthancPlugin'):
         raise Exception()
@@ -279,6 +297,66 @@
     answer['tuple_format'] = ', '.join([ '"' + tuple_format + '"' ] + tuple_target)
     answer['allow_threads'] = allow_threads
 
+    if 'documentation' in f:
+        documentation = {}
+        description = f['documentation'].get('description', [])
+        if len(description) > 0:
+            documentation['short_description'] = description[0].split('.') [0]
+        documentation['description'] = map(lambda x: { 'text' : x }, description)
+
+        args_declaration = []
+        args_documentation = []
+        for a in f['args']:
+            arg_name = ToLowerCase(a['sdk_name'])
+            if a['sdk_type'] == 'const char *':
+                arg_type = 'str'
+            elif a['sdk_type'] == 'float':
+                arg_type = 'float'
+            elif a['sdk_type'] in [ 'const_void_pointer_with_size', 'const void *' ]:
+                arg_type = 'bytes'
+            elif a['sdk_type'] == 'enumeration':
+                arg_type = GetShortName(a['sdk_enumeration'])
+            elif a['sdk_type'] == 'const_object':
+                arg_type = GetShortName(a['sdk_class'])
+            elif a['sdk_type'] in [ 'int32_t', 'uint32_t', 'uint8_t', 'uint16_t', 'uint64_t' ]:
+                arg_type = 'int'
+            else:
+                raise Exception('Argument type not implemented: %s' % a['sdk_type'])
+            args_declaration.append('%s: %s' % (arg_name, arg_type))
+            args_documentation.append({
+                'name' : arg_name,
+                'type' : arg_type,
+                'text' : f['documentation']['args'] [a['sdk_name']],
+            })
+
+        documentation['args_declaration'] = ', '.join(args_declaration)
+        documentation['args'] = args_documentation
+        documentation['has_args'] = len(args_documentation) > 0
+        documentation['has_return'] = True
+        documentation['return_text'] = f['documentation'].get('return', None)
+
+        if f['return_sdk_type'] == 'enumeration':
+            if f['return_sdk_enumeration'] == 'OrthancPluginErrorCode':
+                documentation['has_return'] = False
+                documentation['return_type'] = 'None'
+            else:
+                documentation['return_type'] = GetShortName(f['return_sdk_enumeration'])
+        elif f['return_sdk_type'] == 'object':
+            documentation['return_type'] = GetShortName(f['return_sdk_class'])
+        elif f['return_sdk_type'] == 'void':
+            documentation['has_return'] = False
+            documentation['return_type'] = 'None'
+        elif f['return_sdk_type'] == 'OrthancPluginMemoryBuffer *':
+            documentation['return_type'] = 'bytes'
+        elif f['return_sdk_type'] in [ 'char *', 'const char *' ]:
+            documentation['return_type'] = 'str'
+        elif f['return_sdk_type'] in [ 'int32_t', 'uint32_t', 'int64_t' ]:
+            documentation['return_type'] = 'int'
+        else:
+            raise Exception('Return type not implemented: %s' % f['return_sdk_type'])
+
+        answer['documentation'] = documentation
+
     if len(call_args) > 0:
         answer['call_args'] = ', ' + ', '.join(call_args)
 
@@ -313,12 +391,15 @@
         values.append({
             'key' : ToUpperCase(value['key']),
             'value' : value['value'],
+            'documentation' : value['documentation'],
         })
 
     enumerations.append({
         'name' : e['name'],
+        'short_name' : GetShortName(e['name']),
         'path' : 'sdk_%s.impl.h' % e['name'],
         'values' : values,
+        'documentation' : e['documentation'],
     })
 
     path = 'sdk_%s.impl.h' % e['name']
@@ -392,3 +473,11 @@
         h.write(renderer.render(f.read(), {
             'classes' : sortedClasses,
         }))
+
+with open(os.path.join(ROOT, 'PythonDocumentation.mustache'), 'r') as f:
+    with open(os.path.join(TARGET, 'orthanc.pyi'), 'w') as h:
+        h.write(renderer.render(f.read(), {
+            'classes' : sortedClasses,
+            'enumerations' : sortedEnumerations,
+            'global_functions' : sortedGlobalFunctions,
+        }))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CodeAnalysis/PythonDocumentation.mustache	Tue Jul 02 12:30:16 2024 +0200
@@ -0,0 +1,95 @@
+##
+## Python plugin for Orthanc
+## Copyright (C) 2020-2023 Osimis S.A., Belgium
+## Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+## Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+##
+## This program is free software: you can redistribute it and/or
+## modify it under the terms of the GNU Affero General Public License
+## as published by the Free Software Foundation, either version 3 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
+## Affero General Public License for more details.
+##
+## You should have received a copy of the GNU Affero General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+import enum
+
+{{#enumerations}}
+
+class {{short_name}}(enum.Enum):
+    """
+    {{documentation}}
+    """
+{{#values}}
+
+    """
+    {{documentation}}
+    """
+    {{key}}: int = {{value}},
+{{/values}}
+{{/enumerations}}
+
+
+{{#global_functions}}
+
+{{#documentation.short_description}}
+# {{documentation.short_description}}
+{{/documentation.short_description}}
+def {{short_name}}({{documentation.args_declaration}}) -> {{documentation.return_type}}:
+    """
+{{#documentation.description}}
+    {{text}}
+{{/documentation.description}}
+{{#documentation.has_args}}
+
+    Args:
+      {{#documentation.args}}
+      {{name}} ({{type}}): {{text}}
+      {{/documentation.args}}
+{{/documentation.has_args}}
+{{#documentation.has_return}}
+
+    Returns:
+      {{documentation.return_type}}: {{documentation.return_text}}
+{{/documentation.has_return}}
+    """
+    ...
+{{/global_functions}}
+
+
+{{#classes}}
+class {{short_name}}:
+    ...
+
+{{#methods}}
+{{#documentation.short_description}}
+    # {{documentation.short_description}}
+{{/documentation.short_description}}
+    def {{short_name}}(self{{#documentation.has_args}}, {{/documentation.has_args}}{{documentation.args_declaration}}) -> {{documentation.return_type}}:
+        """
+{{#documentation.description}}
+        {{text}}
+{{/documentation.description}}
+{{#documentation.has_args}}
+
+        Args:
+          {{#documentation.args}}
+          {{name}} ({{type}}): {{text}}
+          {{/documentation.args}}
+{{/documentation.has_args}}
+{{#documentation.has_return}}
+
+        Returns:
+          {{documentation.return_type}}: {{documentation.return_text}}
+{{/documentation.has_return}}
+        """
+        ...
+
+{{/methods}}
+{{/classes}}
--- a/NEWS	Thu Jun 27 21:53:03 2024 +0200
+++ b/NEWS	Tue Jul 02 12:30:16 2024 +0200
@@ -1,6 +1,7 @@
 Pending changes in the mainline
 ===============================
 
+* Created Python documentation for the Orthanc interface, check out "orthanc.pyi"
 * Added Windows builder for Python 3.12