def get_partial_annotation_from_definition( self, property_: PropertyType) -> ast.AST: # Map property type to annotation property_type = property_["type"] # ...map object if property_type == "object": if "oneOf" in property_: ref = self.definitions[property_["oneOf"][0]["$ref"]] if self.definition_is_primitive_alias(ref): annotation = self.get_partial_annotation_from_definition( ref) else: annotation = ast.Name(id=ref["title"]) elif "additionalProperties" in property_: object_name = self.definitions[ property_["additionalProperties"]["$ref"]]["title"] annotation = ast.Subscript( value=ast.Name(id="Dict"), slice=ast.Index(value=ast.Tuple( elts=[ast.Name(id="str"), ast.Name(id=object_name)])), ) else: annotation = ast.Name(id="Dict") # ... map array elif property_type == "array": items = property_.get("items") if isinstance(items, dict): item_annotation = self.get_partial_annotation_from_definition( items) elif isinstance(items, list): raise NotImplementedError( "Tuple for 'array' is not supported: {}".format(property_)) else: item_annotation = ast.Name(id="Any") annotation = ast.Subscript(value=ast.Name(id="List"), slice=ast.Index(value=item_annotation)) # ... map scalar else: python_type = PYTHON_ANNOTATION_MAP[property_["type"]] annotation = ast.Name(id=python_type) # Return return annotation
def get_annotation_from_definition(self, property_: PropertyType, is_required: bool = False) -> ast.AST: annotation = self.get_partial_annotation_from_definition(property_) # Make annotation optional if no default value if not is_required and "default" not in property_: annotation = ast.Subscript(value=ast.Name(id="Optional"), slice=ast.Index(value=annotation)) # Return return annotation
def slice_key_from_data_object(self, key: str) -> ast.Subscript: return ast.Subscript(value=ast.Name(id="data"), slice=ast.Index(value=ast.Str(s=key)))
def make_klass_constructor(self, properties: PropertiesType, requireds: RequiredType) -> ast.FunctionDef: # Prepare body fn_body = [] # Default value for `data` argument if len(properties) > 0: fn_body.append( ast.Assign( targets=[ast.Name(id="data")], value=ast.BoolOp(op=ast.Or(), values=[ ast.Name(id="data"), ast.Dict(keys=[], values=[]) ]), )) for key in sorted(properties.keys()): # Get default value is_required = key in requireds property_ = properties[key] annotation = self.get_annotation_from_definition( property_, is_required=is_required) value = self.get_data_value(key, property_, is_required=is_required) # Build assign expression attribute = ast.AnnAssign( target=ast.Attribute(value=ast.Name(id="self"), attr=key), annotation=annotation, value=value, simple=0, ) # Add to body fn_body.append(attribute) # Bundle function arguments and keywords fn_arguments = ast.arguments( args=[ ast.arg(arg="self", annotation=None), ast.arg( arg="data", annotation=ast.Subscript( value=ast.Name(id="Optional"), slice=ast.Index(value=ast.Name(id="Dict"))), ), ], vararg=None, kwarg=None, kwonlyargs=[], kw_defaults=[], defaults=[ast.NameConstant(value=None)], ) # Generate class constructor fn_init = ast.FunctionDef(name="__init__", args=fn_arguments, body=fn_body, decorator_list=[], returns=None) # Return constructor return fn_init