Sfoglia il codice sorgente

openapi: make the code python 3.5 compatible

It is common to use Ubuntu 16.04 to build snaps. For example,
the official docker container to build snaps is using this old
distribution.

However, Ubuntu 16.04 ships Python 3.5.X which is not compatible
with the f-strings in generate_openapi.py. This is sad, because
we need to use the `.format()` syntax to make it compatible.
Benjamin Tissoires 6 anni fa
parent
commit
8be7eec2ca
1 ha cambiato i file con 72 aggiunte e 68 eliminazioni
  1. 72 68
      openapi/generate_openapi.py

+ 72 - 68
openapi/generate_openapi.py

@@ -23,12 +23,12 @@ def get_req_body_elems(obj, elems):
         right = obj.property.name
         right = obj.property.name
         if left == 'req.body' and right not in elems:
         if left == 'req.body' and right not in elems:
             elems.append(right)
             elems.append(right)
-        return f'{left}.{right}'
+        return '{}.{}'.format(left, right)
     elif obj.type == 'VariableDeclaration':
     elif obj.type == 'VariableDeclaration':
         for s in obj.declarations:
         for s in obj.declarations:
             get_req_body_elems(s, elems)
             get_req_body_elems(s, elems)
     elif obj.type == 'VariableDeclarator':
     elif obj.type == 'VariableDeclarator':
-        if obj.id.type == "ObjectPattern":
+        if obj.id.type == 'ObjectPattern':
             # get_req_body_elems() can't be called directly here:
             # get_req_body_elems() can't be called directly here:
             # const {isAdmin, isNoComments, isCommentOnly} = req.body;
             # const {isAdmin, isNoComments, isCommentOnly} = req.body;
             right = get_req_body_elems(obj.init, elems)
             right = get_req_body_elems(obj.init, elems)
@@ -158,12 +158,14 @@ class EntryPoint(object):
 
 
     def error(self, message):
     def error(self, message):
         if self._raw_doc is None:
         if self._raw_doc is None:
-            sys.stderr.write(f'in {self.schema.name},\n')
-            sys.stderr.write(f'{message}\n')
+            sys.stderr.write('in {},\n'.format(self.schema.name))
+            sys.stderr.write('{}\n'.format(message))
             return
             return
-        sys.stderr.write(f'in {self.schema.name}, lines {self._raw_doc.loc.start.line}-{self._raw_doc.loc.end.line}\n')
-        sys.stderr.write(f'{self._raw_doc.value}\n')
-        sys.stderr.write(f'{message}\n')
+        sys.stderr.write('in {}, lines {}-{}\n'.format(self.schema.name,
+                                                       self._raw_doc.loc.start.line,
+                                                       self._raw_doc.loc.end.line))
+        sys.stderr.write('{}\n'.format(self._raw_doc.value))
+        sys.stderr.write('{}\n'.format(message))
 
 
     @property
     @property
     def doc(self):
     def doc(self):
@@ -233,7 +235,7 @@ class EntryPoint(object):
                 if name.startswith('{'):
                 if name.startswith('{'):
                     param_type = name.strip('{}')
                     param_type = name.strip('{}')
                     if param_type not in ['string', 'number', 'boolean', 'integer', 'array', 'file']:
                     if param_type not in ['string', 'number', 'boolean', 'integer', 'array', 'file']:
-                        self.error(f'Warning, unknown type {param_type}\n allowed values: string, number, boolean, integer, array, file')
+                        self.error('Warning, unknown type {}\n allowed values: string, number, boolean, integer, array, file'.format(param_type))
                     try:
                     try:
                         name, desc = desc.split(maxsplit=1)
                         name, desc = desc.split(maxsplit=1)
                     except ValueError:
                     except ValueError:
@@ -246,7 +248,7 @@ class EntryPoint(object):
 
 
                 # we should not have 2 identical parameter names
                 # we should not have 2 identical parameter names
                 if tag in params:
                 if tag in params:
-                    self.error(f'Warning, overwriting parameter {name}')
+                    self.error('Warning, overwriting parameter {}'.format(name))
 
 
                 params[name] = (param_type, optional, desc)
                 params[name] = (param_type, optional, desc)
 
 
@@ -276,7 +278,7 @@ class EntryPoint(object):
 
 
             # we should not have 2 identical tags but @param or @tag
             # we should not have 2 identical tags but @param or @tag
             if tag in self._doc:
             if tag in self._doc:
-                self.error(f'Warning, overwriting tag {tag}')
+                self.error('Warning, overwriting tag {}'.format(tag))
 
 
             self._doc[tag] = data
             self._doc[tag] = data
 
 
@@ -299,7 +301,7 @@ class EntryPoint(object):
                     current_data = ''
                     current_data = ''
                     line = data
                     line = data
                 else:
                 else:
-                    self.error(f'Unknown tag {tag}, ignoring')
+                    self.error('Unknown tag {}, ignoring'.format(tag))
 
 
             current_data += line + '\n'
             current_data += line + '\n'
 
 
@@ -321,24 +323,24 @@ class EntryPoint(object):
     def print_openapi_param(self, name, indent):
     def print_openapi_param(self, name, indent):
         ptype, poptional, pdesc = self.doc_param(name)
         ptype, poptional, pdesc = self.doc_param(name)
         if pdesc is not None:
         if pdesc is not None:
-            print(f'{" " * indent}description: |')
-            print(f'{" " * (indent + 2)}{pdesc}')
+            print('{}description: |'.format(' ' * indent))
+            print('{}{}'.format(' ' * (indent + 2), pdesc))
         else:
         else:
-            print(f'{" " * indent}description: the {name} value')
+            print('{}description: the {} value'.format(' ' * indent, name))
         if ptype is not None:
         if ptype is not None:
-            print(f'{" " * indent}type: {ptype}')
+            print('{}type: {}'.format(' ' * indent, ptype))
         else:
         else:
-            print(f'{" " * indent}type: string')
+            print('{}type: string'.format(' ' * indent))
         if poptional:
         if poptional:
-            print(f'{" " * indent}required: false')
+            print('{}required: false'.format(' ' * indent))
         else:
         else:
-            print(f'{" " * indent}required: true')
+            print('{}required: true'.format(' ' * indent))
 
 
     @property
     @property
     def operationId(self):
     def operationId(self):
         if 'operation' in self._doc:
         if 'operation' in self._doc:
             return self._doc['operation']
             return self._doc['operation']
-        return f'{self.method_name}_{self.reduced_function_name}'
+        return '{}_{}'.format(self.method_name, self.reduced_function_name)
 
 
     @property
     @property
     def description(self):
     def description(self):
@@ -363,49 +365,49 @@ class EntryPoint(object):
 
 
     def print_openapi_return(self, obj, indent):
     def print_openapi_return(self, obj, indent):
         if isinstance(obj, dict):
         if isinstance(obj, dict):
-            print(f'{" " * indent}type: object')
-            print(f'{" " * indent}properties:')
+            print('{}type: object'.format(' ' * indent))
+            print('{}properties:'.format(' ' * indent))
             for k, v in obj.items():
             for k, v in obj.items():
-                print(f'{" " * (indent + 2)}{k}:')
+                print('{}{}:'.format(' ' * (indent + 2), k))
                 self.print_openapi_return(v, indent + 4)
                 self.print_openapi_return(v, indent + 4)
 
 
         elif isinstance(obj, list):
         elif isinstance(obj, list):
             if len(obj) > 1:
             if len(obj) > 1:
                 self.error('Error while parsing @return tag, an array should have only one type')
                 self.error('Error while parsing @return tag, an array should have only one type')
-            print(f'{" " * indent}type: array')
-            print(f'{" " * indent}items:')
+            print('{}type: array'.format(' ' * indent))
+            print('{}items:'.format(' ' * indent))
             self.print_openapi_return(obj[0], indent + 2)
             self.print_openapi_return(obj[0], indent + 2)
 
 
         elif isinstance(obj, str) or isinstance(obj, unicode):
         elif isinstance(obj, str) or isinstance(obj, unicode):
             rtype = 'type: ' + obj
             rtype = 'type: ' + obj
             if obj == self.schema.name:
             if obj == self.schema.name:
-                rtype = f'$ref: "#/definitions/{obj}"'
-            print(f'{" " * indent}{rtype}')
+                rtype = '$ref: "#/definitions/{}"'.format(obj)
+            print('{}{}'.format(' ' * indent, rtype))
 
 
     def print_openapi(self):
     def print_openapi(self):
         parameters = [token[1:-2] if token.endswith('Id') else token[1:]
         parameters = [token[1:-2] if token.endswith('Id') else token[1:]
                       for token in self.path.split('/')
                       for token in self.path.split('/')
                       if token.startswith(':')]
                       if token.startswith(':')]
 
 
-        print(f'    {self.method_name}:')
+        print('    {}:'.format(self.method_name))
 
 
-        print(f'      operationId: {self.operationId}')
+        print('      operationId: {}'.format(self.operationId))
 
 
         if self.summary is not None:
         if self.summary is not None:
-            print(f'      summary: {self.summary}')
+            print('      summary: {}'.format(self.summary))
 
 
         if self.description is not None:
         if self.description is not None:
-            print(f'      description: |')
+            print('      description: |')
             for line in self.description.split('\n'):
             for line in self.description.split('\n'):
                 if line.strip():
                 if line.strip():
-                    print(f'        {line}')
+                    print('        {}'.format(line))
                 else:
                 else:
                     print('')
                     print('')
 
 
         if len(self.tags) > 0:
         if len(self.tags) > 0:
-            print(f'      tags:')
+            print('      tags:')
             for tag in self.tags:
             for tag in self.tags:
-                print(f'        - {tag}')
+                print('        - {}'.format(tag))
 
 
         # export the parameters
         # export the parameters
         if self.method_name in ('post', 'put'):
         if self.method_name in ('post', 'put'):
@@ -416,14 +418,14 @@ class EntryPoint(object):
             print('      parameters:')
             print('      parameters:')
         if self.method_name in ('post', 'put'):
         if self.method_name in ('post', 'put'):
             for f in self.body_params:
             for f in self.body_params:
-                print(f'''        - name: {f}
-          in: formData''')
+                print('''        - name: {}
+          in: formData'''.format(f))
                 self.print_openapi_param(f, 10)
                 self.print_openapi_param(f, 10)
         for p in parameters:
         for p in parameters:
             if p in self.body_params:
             if p in self.body_params:
                 self.error(' '.join((p, self.path, self.method_name)))
                 self.error(' '.join((p, self.path, self.method_name)))
-            print(f'''        - name: {p}
-          in: path''')
+            print('''        - name: {}
+          in: path'''.format(p))
             self.print_openapi_param(p, 10)
             self.print_openapi_param(p, 10)
         print('''      produces:
         print('''      produces:
         - application/json
         - application/json
@@ -485,7 +487,9 @@ class SchemaProperty(object):
                 return
                 return
 
 
     def __repr__(self):
     def __repr__(self):
-        return f'SchemaProperty({self.name}{"*" if self.required else ""}, {self.doc})'
+        return 'SchemaProperty({}{}, {})'.format(self.name,
+                                                 '*' if self.required else '',
+                                                 self.doc)
 
 
     def print_openapi(self, indent, current_schema, required_properties):
     def print_openapi(self, indent, current_schema, required_properties):
         schema_name = self.schema.name
         schema_name = self.schema.name
@@ -501,11 +505,11 @@ class SchemaProperty(object):
                     if required_properties is not None and required_properties:
                     if required_properties is not None and required_properties:
                         print('    required:')
                         print('    required:')
                         for f in required_properties:
                         for f in required_properties:
-                            print(f'      - {f}')
+                            print('      - {}'.format(f))
                         required_properties.clear()
                         required_properties.clear()
 
 
-                    print(f'''  {subschema}:
-    type: object''')
+                    print('''  {}:
+    type: object'''.format(subschema))
                     return current_schema
                     return current_schema
 
 
             subschema = name.split('.')[0]
             subschema = name.split('.')[0]
@@ -516,23 +520,23 @@ class SchemaProperty(object):
                 if required_properties is not None and required_properties:
                 if required_properties is not None and required_properties:
                     print('    required:')
                     print('    required:')
                     for f in required_properties:
                     for f in required_properties:
-                        print(f'      - {f}')
+                        print('      - {}'.format(f))
                     required_properties.clear()
                     required_properties.clear()
 
 
-                print(f'''  {schema_name}:
+                print('''  {}:
     type: object
     type: object
-    properties:''')
+    properties:'''.format(schema_name))
 
 
         if required_properties is not None and self.required:
         if required_properties is not None and self.required:
             required_properties.append(name)
             required_properties.append(name)
 
 
-        print(f'{" "*indent}{name}:')
+        print('{}{}:'.format(' ' * indent, name))
 
 
         if self.doc is not None:
         if self.doc is not None:
-            print(f'{" "*indent}  description: |')
+            print('{}  description: |'.format(' ' * indent))
             for line in self.doc:
             for line in self.doc:
                 if line.strip():
                 if line.strip():
-                    print(f'{" "*indent}    {line}')
+                    print('{}    {}'.format(' ' * indent, line))
                 else:
                 else:
                     print('')
                     print('')
 
 
@@ -540,31 +544,31 @@ class SchemaProperty(object):
         if ptype in ('enum', 'date'):
         if ptype in ('enum', 'date'):
             ptype = 'string'
             ptype = 'string'
         if ptype != 'object':
         if ptype != 'object':
-            print(f'{" "*indent}  type: {ptype}')
+            print('{}  type: {}'.format(' ' * indent, ptype))
 
 
         if self.type == 'array':
         if self.type == 'array':
-            print(f'{" "*indent}  items:')
+            print('{}  items:'.format(' ' * indent))
             for elem in self.elements:
             for elem in self.elements:
                 if elem == 'object':
                 if elem == 'object':
-                    print(f'{" "*indent}    $ref: "#/definitions/{schema_name + name.capitalize()}"')
+                    print('{}    $ref: "#/definitions/{}"'.format(' ' * indent, schema_name + name.capitalize()))
                 else:
                 else:
-                    print(f'{" "*indent}    type: {elem}')
+                    print('{}    type: {}'.format(' ' * indent, elem))
                     if not self.required:
                     if not self.required:
-                        print(f'{" "*indent}    x-nullable: true')
+                        print('{}    x-nullable: true'.format(' ' * indent))
 
 
         elif self.type == 'object':
         elif self.type == 'object':
             if self.blackbox:
             if self.blackbox:
-                print(f'{" "*indent}  type: object')
+                print('{}  type: object'.format(' ' * indent))
             else:
             else:
-                print(f'{" "*indent}  $ref: "#/definitions/{schema_name + name.capitalize()}"')
+                print('{}  $ref: "#/definitions/{}"'.format(' ' * indent, schema_name + name.capitalize()))
 
 
         elif self.type == 'enum':
         elif self.type == 'enum':
-            print(f'{" "*indent}  enum:')
+            print('{}  enum:'.format(' ' * indent))
             for enum in self.enum:
             for enum in self.enum:
-                print(f'{" "*indent}    - {enum}')
+                print('{}    - {}'.format(' ' * indent, enum))
 
 
         if '.' not in self.name and not self.required:
         if '.' not in self.name and not self.required:
-            print(f'{" "*indent}  x-nullable: true')
+            print('{}  x-nullable: true'.format(' ' * indent))
 
 
         return schema_name
         return schema_name
 
 
@@ -620,10 +624,10 @@ class Schemas(object):
         if self.fields is None:
         if self.fields is None:
             return
             return
 
 
-        print(f'  {self.name}:')
+        print('  {}:'.format(self.name))
         print('    type: object')
         print('    type: object')
         if self.doc is not None:
         if self.doc is not None:
-            print(f'    description: {self.doc}')
+            print('    description: {}'.format(self.doc))
 
 
         print('    properties:')
         print('    properties:')
 
 
@@ -636,7 +640,7 @@ class Schemas(object):
         if required_properties:
         if required_properties:
             print('    required:')
             print('    required:')
             for f in required_properties:
             for f in required_properties:
-                print(f'      - {f}')
+                print('      - {}'.format(f))
 
 
         # then print the references
         # then print the references
         current = None
         current = None
@@ -648,7 +652,7 @@ class Schemas(object):
         if required_properties:
         if required_properties:
             print('    required:')
             print('    required:')
             for f in required_properties:
             for f in required_properties:
-                print(f'      - {f}')
+                print('      - {}'.format(f))
 
 
         required_properties = []
         required_properties = []
         # then print the references in the references
         # then print the references in the references
@@ -658,7 +662,7 @@ class Schemas(object):
         if required_properties:
         if required_properties:
             print('    required:')
             print('    required:')
             for f in required_properties:
             for f in required_properties:
-                print(f'      - {f}')
+                print('      - {}'.format(f))
 
 
 
 
 def parse_schemas(schemas_dir):
 def parse_schemas(schemas_dir):
@@ -731,10 +735,10 @@ def parse_schemas(schemas_dir):
 
 
 
 
 def generate_openapi(schemas, entry_points, version):
 def generate_openapi(schemas, entry_points, version):
-    print(f'''swagger: '2.0'
+    print('''swagger: '2.0'
 info:
 info:
   title: Wekan REST API
   title: Wekan REST API
-  version: {version}
+  version: {0}
   description: |
   description: |
     The REST API allows you to control and extend Wekan with ease.
     The REST API allows you to control and extend Wekan with ease.
 
 
@@ -866,7 +870,7 @@ paths:
         default:
         default:
           description: |
           description: |
             Error in registration
             Error in registration
-''')
+'''.format(version))
 
 
     # GET and POST on the same path are valid, we need to reshuffle the paths
     # GET and POST on the same path are valid, we need to reshuffle the paths
     # with the path as the sorting key
     # with the path as the sorting key
@@ -880,7 +884,7 @@ paths:
     sorted_paths.sort()
     sorted_paths.sort()
 
 
     for path in sorted_paths:
     for path in sorted_paths:
-        print(f'  {methods[path][0].url}:')
+        print('  {}:'.format(methods[path][0].url))
 
 
         for ep in methods[path]:
         for ep in methods[path]:
             ep.print_openapi()
             ep.print_openapi()
@@ -897,9 +901,9 @@ paths:
 def main():
 def main():
     parser = argparse.ArgumentParser(description='Generate an OpenAPI 2.0 from the given JS schemas.')
     parser = argparse.ArgumentParser(description='Generate an OpenAPI 2.0 from the given JS schemas.')
     script_dir = os.path.dirname(os.path.realpath(__file__))
     script_dir = os.path.dirname(os.path.realpath(__file__))
-    parser.add_argument('--release', default=f'git-master', nargs=1,
+    parser.add_argument('--release', default='git-master', nargs=1,
                         help='the current version of the API, can be retrieved by running `git describe --tags --abbrev=0`')
                         help='the current version of the API, can be retrieved by running `git describe --tags --abbrev=0`')
-    parser.add_argument('dir', default=f'{script_dir}/../models', nargs='?',
+    parser.add_argument('dir', default='{}/../models'.format(script_dir), nargs='?',
                         help='the directory where to look for schemas')
                         help='the directory where to look for schemas')
 
 
     args = parser.parse_args()
     args = parser.parse_args()