def _generate_struct_class_repr(self, data_type): """ Generates something like: def __repr__(self): return 'Employee(first_name={!r}, last_name={!r}, age={!r})'.format( self._first_name_value, self._last_name_value, self._age_value, ) """ self.emit('def __repr__(self):') with self.indent(): if data_type.all_fields: constructor_kwargs_fmt = ', '.join( '{}={{!r}}'.format(fmt_var(f.name, True)) for f in data_type.all_fields) self.emit("return '{}({})'.format(".format( class_name_for_data_type(data_type), constructor_kwargs_fmt, )) with self.indent(): for f in data_type.all_fields: self.emit("self._{}_value,".format(fmt_var(f.name))) self.emit(")") else: self.emit("return '%s()'" % class_name_for_data_type(data_type)) self.emit()
def _generate_union_class_reflection_attributes(self, ns, data_type): """ Adds a class attribute for each union member assigned to a validator. Also adds an attribute that is a map from tag names to validators. """ class_name = fmt_class(data_type.name) for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor( ns, field.data_type) self.emit('{}._{}_validator = {}'.format(class_name, field_name, validator_name)) with self.block('{}._tagmap ='.format(class_name)): for field in data_type.fields: var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) self.emit("'{}': {},".format(var_name, validator_name)) if data_type.parent_type: self.emit('{0}._tagmap.update({1}._tagmap)'.format( class_name, class_name_for_data_type(data_type.parent_type, ns))) self.emit()
def _generate_union_class_reflection_attributes(self, ns, data_type): """ Adds a class attribute for each union member assigned to a validator. Also adds an attribute that is a map from tag names to validators. """ class_name = fmt_class(data_type.name) for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor( ns, field.data_type) self.emit('{}._{}_validator = {}'.format( class_name, field_name, validator_name)) with self.block('{}._tagmap ='.format(class_name)): for field in data_type.fields: var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) self.emit("'{}': {},".format(var_name, validator_name)) if data_type.parent_type: self.emit('{0}._tagmap.update({1}._tagmap)'.format( class_name, class_name_for_data_type(data_type.parent_type, ns))) self.emit()
def _generate_struct_class_repr(self, data_type): """ Generates something like: def __repr__(self): return 'Employee(first_name={!r}, last_name={!r}, age={!r})'.format( self._first_name_value, self._last_name_value, self._age_value, ) """ self.emit('def __repr__(self):') with self.indent(): if data_type.all_fields: constructor_kwargs_fmt = ', '.join( '{}={{!r}}'.format(fmt_var(f.name, True)) for f in data_type.all_fields) self.emit("return '{}({})'.format(".format( class_name_for_data_type(data_type), constructor_kwargs_fmt, )) with self.indent(): for f in data_type.all_fields: self.emit("self._{}_value,".format(fmt_var(f.name))) self.emit(")") else: self.emit("return '%s()'" % class_name_for_data_type(data_type)) self.emit()
def _generate_annotation_type_class_init(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None args = ['self'] for param in annotation_type.params: param_name = fmt_var(param.name, True) default_value = (self._generate_python_value(ns, param.default) if param.has_default else 'None') args.append('{}={}'.format(param_name, default_value)) self.generate_multiline_list(args, before='def __init__', after=':') with self.indent(): for param in annotation_type.params: self.emit('self._{0} = {0}'.format(fmt_var(param.name, True))) self.emit()
def _generate_union_class_reflection_attributes(self, ns, data_type): """ Adds a class attribute for each union member assigned to a validator. Also adds an attribute that is a map from tag names to validators. """ class_name = fmt_class(data_type.name) for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor( ns, field.data_type) full_validator_name = '{}._{}_validator'.format( class_name, field_name) self.emit('{} = {}'.format(full_validator_name, validator_name)) if field.redactor: self._generate_redactor(full_validator_name, field.redactor) # generate _all_fields_ for each omitted caller (and public) child_omitted_callers = data_type.get_all_omitted_callers() parent_omitted_callers = data_type.parent_type.get_all_omitted_callers() if \ data_type.parent_type else set([]) all_omitted_callers = child_omitted_callers | parent_omitted_callers if len(all_omitted_callers) != 0: self.emit('{}._permissioned_tagmaps = {}'.format( class_name, all_omitted_callers)) for omitted_caller in all_omitted_callers | {None}: is_public = omitted_caller is None tagmap_name = '_tagmap' if is_public else '_{}_tagmap'.format( omitted_caller) caller_in_parent = data_type.parent_type and ( is_public or omitted_caller in parent_omitted_callers) with self.block('{}.{} ='.format(class_name, tagmap_name)): for field in data_type.fields: if field.omitted_caller != omitted_caller: continue var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) self.emit("'{}': {},".format(var_name, validator_name)) if caller_in_parent: self.emit('{0}.{1}.update({2}.{1})'.format( class_name, tagmap_name, class_name_for_data_type(data_type.parent_type, ns))) self.emit()
def _generate_union_class(self, ns, data_type): # type: (ApiNamespace, Union) -> None """Defines a Python class that represents a union in Stone.""" self.emit(self._class_declaration_for_type(ns, data_type)) with self.indent(): self.emit('"""') if data_type.doc: self.emit_wrapped_text( self.process_doc(data_type.doc, self._docf)) self.emit() self.emit_wrapped_text( 'This class acts as a tagged union. Only one of the ``is_*`` ' 'methods will return true. To get the associated value of a ' 'tag (if one exists), use the corresponding ``get_*`` method.') if data_type.has_documented_fields(): self.emit() for field in data_type.fields: if not field.doc: continue if is_void_type(field.data_type): ivar_doc = ':ivar {}: {}'.format( fmt_var(field.name), self.process_doc(field.doc, self._docf)) elif is_user_defined_type(field.data_type): ivar_doc = ':ivar {} {}: {}'.format( fmt_class(field.data_type.name), fmt_var(field.name), self.process_doc(field.doc, self._docf)) else: ivar_doc = ':ivar {} {}: {}'.format( self._python_type_mapping(ns, field.data_type), fmt_var(field.name), field.doc) self.emit_wrapped_text(ivar_doc, subsequent_prefix=' ') self.emit('"""') self.emit() self._generate_union_class_vars(data_type) self._generate_union_class_variant_creators(ns, data_type) self._generate_union_class_is_set(data_type) self._generate_union_class_get_helpers(ns, data_type) self._generate_union_class_repr(data_type) self.emit('{0}_validator = bv.Union({0})'.format( class_name_for_data_type(data_type) )) self.emit()
def _generate_union_class(self, ns, data_type): # type: (ApiNamespace, Union) -> None """Defines a Python class that represents a union in Stone.""" self.emit(self._class_declaration_for_type(ns, data_type)) with self.indent(): self.emit('"""') if data_type.doc: self.emit_wrapped_text( self.process_doc(data_type.doc, self._docf)) self.emit() self.emit_wrapped_text( 'This class acts as a tagged union. Only one of the ``is_*`` ' 'methods will return true. To get the associated value of a ' 'tag (if one exists), use the corresponding ``get_*`` method.') if data_type.has_documented_fields(): self.emit() for field in data_type.fields: if not field.doc: continue if is_void_type(field.data_type): ivar_doc = ':ivar {}: {}'.format( fmt_var(field.name), self.process_doc(field.doc, self._docf)) elif is_user_defined_type(field.data_type): ivar_doc = ':ivar {} {}: {}'.format( fmt_class(field.data_type.name), fmt_var(field.name), self.process_doc(field.doc, self._docf)) else: ivar_doc = ':ivar {} {}: {}'.format( self._python_type_mapping(ns, field.data_type), fmt_var(field.name), field.doc) self.emit_wrapped_text(ivar_doc, subsequent_prefix=' ') self.emit('"""') self.emit() self._generate_union_class_vars(data_type) self._generate_union_class_variant_creators(ns, data_type) self._generate_union_class_is_set(data_type) self._generate_union_class_get_helpers(ns, data_type) self._generate_union_class_repr(data_type) self.emit('{0}_validator = bv.Union({0})'.format( class_name_for_data_type(data_type) )) self.emit()
def _generate_annotation_type_class_slots(self, annotation_type): # type: (AnnotationType) -> None with self.block('__slots__ =', delim=('[', ']')): for param in annotation_type.params: param_name = fmt_var(param.name, True) self.emit("'_{}',".format(param_name)) self.emit()
def _generate_struct_class_custom_annotations(self, ns, data_type): """ The _process_custom_annotations function allows client code to access custom annotations defined in the spec. """ self.emit( 'def _process_custom_annotations(self, annotation_type, field_path, processor):' ) with self.indent(), emit_pass_if_nothing_emitted(self): self.emit(( 'super({}, self)._process_custom_annotations(annotation_type, field_path, ' 'processor)').format(class_name_for_data_type(data_type))) self.emit() for field in data_type.fields: field_name = fmt_var(field.name, check_reserved=True) for annotation_type, processor in self._generate_custom_annotation_processors( ns, field.data_type, field.custom_annotations): annotation_class = class_name_for_annotation_type( annotation_type, ns) self.emit( 'if annotation_type is {}:'.format(annotation_class)) with self.indent(): self.emit('self.{} = {}'.format( field_name, generate_func_call( processor, args=[ "'{{}}.{}'.format(field_path)".format( field_name), 'self.{}'.format(field_name), ]))) self.emit()
def _generate_annotation_type_class(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None """Defines a Python class that represents an annotation type in Stone.""" self.emit('class {}(bb.AnnotationType):'.format( class_name_for_annotation_type(annotation_type, ns))) with self.indent(): if annotation_type.has_documented_type_or_params(): self.emit('"""') if annotation_type.doc: self.emit_wrapped_text( self.process_doc(annotation_type.doc, self._docf)) if annotation_type.has_documented_params(): self.emit() for param in annotation_type.params: if not param.doc: continue self.emit_wrapped_text(':ivar {}: {}'.format( fmt_var(param.name, True), self.process_doc(param.doc, self._docf)), subsequent_prefix=' ') self.emit('"""') self.emit() self._generate_annotation_type_class_slots(annotation_type) self._generate_annotation_type_class_init(ns, annotation_type) self._generate_annotation_type_class_properties( ns, annotation_type) self.emit()
def _generate_union_class_reflection_attributes(self, ns, data_type): """ Adds a class attribute for each union member assigned to a validator. Also adds an attribute that is a map from tag names to validators. """ class_name = fmt_class(data_type.name) for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor( ns, field.data_type) full_validator_name = '{}._{}_validator'.format(class_name, field_name) self.emit('{} = {}'.format(full_validator_name, validator_name)) if field.redactor: self._generate_redactor(full_validator_name, field.redactor) # generate _all_fields_ for each omitted caller (and public) child_omitted_callers = data_type.get_all_omitted_callers() parent_omitted_callers = data_type.parent_type.get_all_omitted_callers() if \ data_type.parent_type else set([]) all_omitted_callers = child_omitted_callers | parent_omitted_callers if len(all_omitted_callers) != 0: self.emit('{}._permissioned_tagmaps = {}'.format(class_name, all_omitted_callers)) for omitted_caller in all_omitted_callers | {None}: is_public = omitted_caller is None tagmap_name = '_tagmap' if is_public else '_{}_tagmap'.format(omitted_caller) caller_in_parent = data_type.parent_type and (is_public or omitted_caller in parent_omitted_callers) with self.block('{}.{} ='.format(class_name, tagmap_name)): for field in data_type.fields: if field.omitted_caller != omitted_caller: continue var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format(class_name, var_name) self.emit("'{}': {},".format(var_name, validator_name)) if caller_in_parent: self.emit('{0}.{1}.update({2}.{1})'.format( class_name, tagmap_name, class_name_for_data_type(data_type.parent_type, ns)) ) self.emit()
def _generate_python_value(self, namespace, value): if is_tag_ref(value): return '{}.{}.{}'.format( fmt_namespace(namespace.name), class_name_for_data_type(value.union_data_type), fmt_var(value.tag_name)) else: return fmt_obj(value)
def _generate_struct_attributes_defaults(self, ns, data_type): # Default values can cross-reference, so we also set them after classes. class_name = class_name_for_data_type(data_type) for field in data_type.fields: if field.has_default: self.emit("{}.{}.default = {}".format( class_name, fmt_var(field.name), self._generate_python_value(ns, field.default)))
def _generate_python_value(self, namespace, value): if is_tag_ref(value): return '{}.{}.{}'.format( fmt_namespace(namespace.name), class_name_for_data_type(value.union_data_type), fmt_var(value.tag_name)) else: return fmt_obj(value)
def _generate_python_value(self, ns, value): if is_tag_ref(value): ref = '{}.{}'.format( class_name_for_data_type(value.union_data_type), fmt_var(value.tag_name)) if ns != value.union_data_type.namespace: ref = '%s.%s' % (value.union_data_type.namespace.name, ref) return ref else: return fmt_obj(value)
def _generate_struct_class_init(self, data_type): """ Generates constructor. The constructor takes all possible fields as optional arguments. Any argument that is set on construction sets the corresponding field for the instance. """ args = ['self'] for field in data_type.all_fields: field_name_reserved_check = fmt_var(field.name, True) args.append('%s=None' % field_name_reserved_check) self.generate_multiline_list(args, before='def __init__', after=':') with self.indent(): lineno = self.lineno # Call the parent constructor if a super type exists if data_type.parent_type: class_name = class_name_for_data_type(data_type) all_parent_fields = [ fmt_func(f.name, True) for f in data_type.parent_type.all_fields ] self.generate_multiline_list( all_parent_fields, before='super({}, self).__init__'.format(class_name)) # initialize each field for field in data_type.fields: field_var_name = fmt_var(field.name) self.emit('self._{}_value = None'.format(field_var_name)) self.emit('self._{}_present = False'.format(field_var_name)) # handle arguments that were set for field in data_type.fields: field_var_name = fmt_var(field.name, True) self.emit('if {} is not None:'.format(field_var_name)) with self.indent(): self.emit('self.{0} = {0}'.format(field_var_name)) if lineno == self.lineno: self.emit('pass') self.emit()
def _generate_python_value(self, ns, value): if is_tag_ref(value): ref = '{}.{}'.format( class_name_for_data_type(value.union_data_type), fmt_var(value.tag_name)) if ns != value.union_data_type.namespace: ref = '%s.%s' % (value.union_data_type.namespace.name, ref) return ref else: return fmt_obj(value)
def _generate_custom_annotation_instance(self, ns, annotation): """ Generates code to construct an instance of an annotation type object with parameters from the specified annotation. """ annotation_class = class_name_for_annotation_type( annotation.annotation_type, ns) return generate_func_call( annotation_class, kwargs=((fmt_var(k, True), self._generate_python_value(ns, v)) for k, v in annotation.kwargs.items()))
def _generate_struct_class_slots(self, data_type): """Creates a slots declaration for struct classes. Slots are an optimization in Python. They reduce the memory footprint of instances since attributes cannot be added after declaration. """ with self.block('__slots__ =', delim=('[', ']')): for field in data_type.fields: field_name = fmt_var(field.name) self.emit("'_%s_value'," % field_name) self.emit()
def _generate_struct_class_init(self, data_type): """ Generates constructor. The constructor takes all possible fields as optional arguments. Any argument that is set on construction sets the corresponding field for the instance. """ args = ['self'] for field in data_type.all_fields: field_name_reserved_check = fmt_var(field.name, True) args.append('%s=None' % field_name_reserved_check) self.generate_multiline_list(args, before='def __init__', after=':') with self.indent(): lineno = self.lineno # Call the parent constructor if a super type exists if data_type.parent_type: class_name = class_name_for_data_type(data_type) all_parent_fields = [fmt_func(f.name, True) for f in data_type.parent_type.all_fields] self.generate_multiline_list( all_parent_fields, before='super({}, self).__init__'.format(class_name)) # initialize each field for field in data_type.fields: field_var_name = fmt_var(field.name) self.emit('self._{}_value = None'.format(field_var_name)) self.emit('self._{}_present = False'.format(field_var_name)) # handle arguments that were set for field in data_type.fields: field_var_name = fmt_var(field.name, True) self.emit('if {} is not None:'.format(field_var_name)) with self.indent(): self.emit('self.{0} = {0}'.format(field_var_name)) if lineno == self.lineno: self.emit('pass') self.emit()
def _generate_annotation_type_class_properties(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None for param in annotation_type.params: prop_name = fmt_var(param.name, True) param_type = self.map_stone_type_to_pep484_type(ns, param.data_type) self.emit('@property') self.emit('def {prop_name}(self) -> {param_type}: ...'.format( prop_name=prop_name, param_type=param_type, )) self.emit()
def _generate_struct_class_slots(self, data_type): """Creates a slots declaration for struct classes. Slots are an optimization in Python. They reduce the memory footprint of instances since attributes cannot be added after declaration. """ with self.block('__slots__ =', delim=('[', ']')): for field in data_type.fields: field_name = fmt_var(field.name) self.emit("'_%s_value'," % field_name) self.emit("'_%s_present'," % field_name) self.emit()
def _generate_annotation_type_class_properties(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None for param in annotation_type.params: prop_name = fmt_var(param.name, True) param_type = self.map_stone_type_to_pep484_type(ns, param.data_type) self.emit('@property') self.emit('def {prop_name}(self) -> {param_type}: ...'.format( prop_name=prop_name, param_type=param_type, )) self.emit()
def _generate_namespace_module(self, namespace): for data_type in namespace.linearize_data_types(): if not is_struct_type(data_type): # Only handle user-defined structs (avoid unions and primitives) continue # Define a class for each struct class_def = 'class {}(object):'.format(fmt_class(data_type.name)) self.emit(class_def) with self.indent(): if data_type.doc: self.emit('"""') self.emit_wrapped_text(data_type.doc) self.emit('"""') self.emit() # Define constructor to take each field args = ['self'] for field in data_type.fields: args.append(fmt_var(field.name)) self.generate_multiline_list(args, 'def __init__', ':') with self.indent(): if data_type.fields: self.emit() # Body of init should assign all init vars for field in data_type.fields: if field.doc: self.emit_wrapped_text(field.doc, '# ', '# ') member_name = fmt_var(field.name) self.emit('self.{0} = {0}'.format(member_name)) else: self.emit('pass') self.emit()
def _generate_namespace_module(self, namespace): for data_type in namespace.linearize_data_types(): if not is_struct_type(data_type): # Only handle user-defined structs (avoid unions and primitives) continue # Define a class for each struct class_def = 'class {}(object):'.format(fmt_class(data_type.name)) self.emit(class_def) with self.indent(): if data_type.doc: self.emit('"""') self.emit_wrapped_text(data_type.doc) self.emit('"""') self.emit() # Define constructor to take each field args = ['self'] for field in data_type.fields: args.append(fmt_var(field.name)) self.generate_multiline_list(args, 'def __init__', ':') with self.indent(): if data_type.fields: self.emit() # Body of init should assign all init vars for field in data_type.fields: if field.doc: self.emit_wrapped_text(field.doc, '# ', '# ') member_name = fmt_var(field.name) self.emit('self.{0} = {0}'.format(member_name)) else: self.emit('pass') self.emit()
def _generate_struct_class_init(self, ns, struct): # type: (ApiNamespace, Struct) -> None args = [] for field in struct.all_fields: field_name_reserved_check = fmt_var(field.name, True) field_type = self.map_stone_type_to_pep484_type( ns, field.data_type) args.append("{field_name}: {field_type} = ...".format( field_name=field_name_reserved_check, field_type=field_type, )) self.generate_multiline_list(before='def __init__', items=["self"] + args, after=' -> None: ...')
def _generate_struct_class_init(self, ns, struct): # type: (ApiNamespace, Struct) -> None args = ["self"] for field in struct.all_fields: field_name_reserved_check = fmt_var(field.name, True) field_type = self.map_stone_type_to_pep484_type(ns, field.data_type) if field.has_default: self.import_tracker._register_typing_import('Optional') field_type = 'Optional[{}]'.format(field_type) args.append("{field_name}: {field_type} = ...".format( field_name=field_name_reserved_check, field_type=field_type)) self.generate_multiline_list(args, before='def __init__', after=' -> None: ...')
def _generate_struct_class_init(self, ns, struct): # type: (ApiNamespace, Struct) -> None args = ["self"] for field in struct.all_fields: field_name_reserved_check = fmt_var(field.name, True) field_type = self.map_stone_type_to_pep484_type(ns, field.data_type) if not is_nullable_type(field.data_type): self.import_tracker._register_typing_import('Optional') field_type = 'Optional[{}]'.format(field_type) args.append("{field_name}: {field_type} = ...".format( field_name=field_name_reserved_check, field_type=field_type)) self.generate_multiline_list(args, before='def __init__', after=' -> None: ...')
def _generate_annotation_type_class_init(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None args = [] for param in annotation_type.params: param_name = fmt_var(param.name, True) param_type = self.map_stone_type_to_pep484_type( ns, param.data_type) args.append("{param_name}: {param_type} = ...".format( param_name=param_name, param_type=param_type, )) self.generate_multiline_list(before='def __init__', items=["self"] + args, after=' -> None: ...') self.emit()
def _generate_union_class_vars(self, ns, data_type): # type: (ApiNamespace, Union) -> None lineno = self.lineno # Generate stubs for class variables so that IDEs like PyCharms have an # easier time detecting their existence. for field in data_type.fields: if is_void_type(field.data_type): field_name = fmt_var(field.name) field_type = class_name_for_data_type(data_type, ns) self.emit('{field_name} = ... # type: {field_type}'.format( field_name=field_name, field_type=field_type, )) if lineno != self.lineno: self.emit()
def _generate_union_class_vars(self, ns, data_type): # type: (ApiNamespace, Union) -> None lineno = self.lineno # Generate stubs for class variables so that IDEs like PyCharms have an # easier time detecting their existence. for field in data_type.fields: if is_void_type(field.data_type): field_name = fmt_var(field.name) field_type = class_name_for_data_type(data_type, ns) self.emit('{field_name} = ... # type: {field_type}'.format( field_name=field_name, field_type=field_type, )) if lineno != self.lineno: self.emit()
def _generate_struct_class_init(self, ns, struct): # type: (ApiNamespace, Struct) -> None args = [] for field in struct.all_fields: field_name_reserved_check = fmt_var(field.name, True) field_type = self.map_stone_type_to_pep484_type(ns, field.data_type) args.append( "{field_name}: {field_type} = ...".format( field_name=field_name_reserved_check, field_type=field_type, ) ) self.generate_multiline_list( before='def __init__', items=["self"] + args, after=' -> None: ...')
def _generate_annotation_type_class_init(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None args = ['self'] for param in annotation_type.params: param_name = fmt_var(param.name, True) param_type = self.map_stone_type_to_pep484_type(ns, param.data_type) if not is_nullable_type(param.data_type): self.import_tracker._register_typing_import('Optional') param_type = 'Optional[{}]'.format(param_type) args.append( "{param_name}: {param_type} = ...".format( param_name=param_name, param_type=param_type)) self.generate_multiline_list(args, before='def __init__', after=' -> None: ...') self.emit()
def _generate_annotation_type_class_init(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None args = ['self'] for param in annotation_type.params: param_name = fmt_var(param.name, True) param_type = self.map_stone_type_to_pep484_type(ns, param.data_type) if not is_nullable_type(param.data_type): self.import_tracker._register_typing_import('Optional') param_type = 'Optional[{}]'.format(param_type) args.append( "{param_name}: {param_type} = ...".format( param_name=param_name, param_type=param_type)) self.generate_multiline_list(args, before='def __init__', after=' -> None: ...') self.emit()
def _generate_annotation_type_class_properties(self, ns, annotation_type): # type: (ApiNamespace, AnnotationType) -> None for param in annotation_type.params: param_name = fmt_var(param.name, True) prop_name = fmt_func(param.name, True) self.emit('@property') self.emit('def {}(self):'.format(prop_name)) with self.indent(): self.emit('"""') if param.doc: self.emit_wrapped_text( self.process_doc(param.doc, self._docf)) # Sphinx wants an extra line between the text and the # rtype declaration. self.emit() self.emit(':rtype: {}'.format( self._python_type_mapping(ns, param.data_type))) self.emit('"""') self.emit('return self._{}'.format(param_name)) self.emit()
def _generate_union_class_vars(self, data_type): """ Adds a _catch_all_ attribute to each class. Also, adds a placeholder attribute for the construction of union members of void type. """ lineno = self.lineno if data_type.catch_all_field: self.emit("_catch_all = '%s'" % data_type.catch_all_field.name) elif not data_type.parent_type: self.emit('_catch_all = None') # Generate stubs for class variables so that IDEs like PyCharms have an # easier time detecting their existence. for field in data_type.fields: if is_void_type(field.data_type): field_name = fmt_var(field.name) self.emit('# Attribute is overwritten below the class definition') self.emit('{} = None'.format(field_name)) if lineno != self.lineno: self.emit()
def _generate_union_class_vars(self, data_type): """ Adds a _catch_all_ attribute to each class. Also, adds a placeholder attribute for the construction of union members of void type. """ lineno = self.lineno if data_type.catch_all_field: self.emit("_catch_all = '%s'" % data_type.catch_all_field.name) elif not data_type.parent_type: self.emit('_catch_all = None') # Generate stubs for class variables so that IDEs like PyCharms have an # easier time detecting their existence. for field in data_type.fields: if is_void_type(field.data_type): field_name = fmt_var(field.name) self.emit('# Attribute is overwritten below the class definition') self.emit('{} = None'.format(field_name)) if lineno != self.lineno: self.emit()
def _generate_struct_class_init(self, ns, struct): # type: (ApiNamespace, Struct) -> None args = [] for field in struct.all_fields: field_name_reserved_check = fmt_var(field.name, True) field_type = self.map_stone_type_to_pep484_type( ns, field.data_type) # The constructor takes all possible fields as optional arguments if not is_nullable_type(field.data_type) and not is_void_type( field.data_type): self.import_tracker._register_typing_import('Optional') field_type = 'Optional[{}]'.format(field_type) args.append("{field_name}: {field_type} = ...".format( field_name=field_name_reserved_check, field_type=field_type, )) self.generate_multiline_list(before='def __init__', items=["self"] + args, after=' -> None: ...')
def _generate_struct_class(self, ns, data_type): # type: (ApiNamespace, Struct) -> None """Defines a Python class that represents a struct in Stone.""" self.emit(self._class_declaration_for_type(ns, data_type)) with self.indent(): if data_type.has_documented_type_or_fields(): self.emit('"""') if data_type.doc: self.emit_wrapped_text( self.process_doc(data_type.doc, self._docf)) if data_type.has_documented_fields(): self.emit() for field in data_type.fields: if not field.doc: continue self.emit_wrapped_text(':ivar {}: {}'.format( fmt_var(field.name), self.process_doc(field.doc, self._docf)), subsequent_prefix=' ') self.emit('"""') self.emit() self._generate_struct_class_slots(data_type) self._generate_struct_class_has_required_fields(data_type) self._generate_struct_class_init(data_type) self._generate_struct_class_properties(ns, data_type) self._generate_struct_class_repr(data_type) if data_type.has_enumerated_subtypes(): validator = 'StructTree' else: validator = 'Struct' self.emit('{0}_validator = bv.{1}({0})'.format( class_name_for_data_type(data_type), validator, )) self.emit()
def _generate_struct_class(self, ns, data_type): # type: (ApiNamespace, Struct) -> None """Defines a Python class that represents a struct in Stone.""" self.emit(self._class_declaration_for_type(ns, data_type)) with self.indent(): if data_type.has_documented_type_or_fields(): self.emit('"""') if data_type.doc: self.emit_wrapped_text( self.process_doc(data_type.doc, self._docf)) if data_type.has_documented_fields(): self.emit() for field in data_type.fields: if not field.doc: continue self.emit_wrapped_text(':ivar {}: {}'.format( fmt_var(field.name), self.process_doc(field.doc, self._docf)), subsequent_prefix=' ') self.emit('"""') self.emit() self._generate_struct_class_slots(data_type) self._generate_struct_class_has_required_fields(data_type) self._generate_struct_class_init(data_type) self._generate_struct_class_properties(ns, data_type) self._generate_struct_class_repr(data_type) if data_type.has_enumerated_subtypes(): validator = 'StructTree' else: validator = 'Struct' self.emit('{0}_validator = bv.{1}({0})'.format( class_name_for_data_type(data_type), validator, )) self.emit()
def _generate_struct_class_reflection_attributes(self, ns, data_type): """ Generates two class attributes: * _all_field_names_: Set of all field names including inherited fields. * _all_fields_: List of tuples, where each tuple is (name, validator). If a struct has enumerated subtypes, then two additional attributes are generated: * _field_names_: Set of all field names excluding inherited fields. * _fields: List of tuples, where each tuple is (name, validator), and excludes inherited fields. These are needed because serializing a struct with enumerated subtypes requires knowing the fields defined in each level of the hierarchy. """ class_name = class_name_for_data_type(data_type) if data_type.parent_type: parent_type_class_name = class_name_for_data_type( data_type.parent_type, ns) else: parent_type_class_name = None for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor(ns, field.data_type) full_validator_name = '{}._{}_validator'.format(class_name, field_name) self.emit('{} = {}'.format(full_validator_name, validator_name)) if field.redactor: self._generate_redactor(full_validator_name, field.redactor) # Generate `_all_field_names_` and `_all_fields_` for every omitted caller (and public). # As an edge case, we union omitted callers with None in the case when the object has no # public fields, as we still need to generate public attributes (`_field_names_` etc) child_omitted_callers = data_type.get_all_omitted_callers() | {None} parent_omitted_callers = data_type.parent_type.get_all_omitted_callers() if \ data_type.parent_type else set([]) for omitted_caller in child_omitted_callers | parent_omitted_callers: is_public = omitted_caller is None map_name_prefix = '' if is_public else '_{}'.format(omitted_caller) caller_in_parent = data_type.parent_type and (is_public or omitted_caller in parent_omitted_callers) # generate `_all_field_names_` names_map_name = '{}_field_names_'.format(map_name_prefix) all_names_map_name = '_all{}_field_names_'.format(map_name_prefix) if data_type.is_member_of_enumerated_subtypes_tree(): if is_public or omitted_caller in child_omitted_callers: self.generate_multiline_list( [ "'%s'" % field.name for field in data_type.fields if field.omitted_caller == omitted_caller ], before='{}.{} = set('.format(class_name, names_map_name), after=')', delim=('[', ']'), compact=False) if caller_in_parent: self.emit('{0}.{3} = {1}.{3}.union({0}.{2})' .format(class_name, parent_type_class_name, names_map_name, all_names_map_name)) else: self.emit('{0}.{2} = {0}.{1}'.format(class_name, names_map_name, all_names_map_name)) else: if caller_in_parent: before = '{0}.{1} = {2}.{1}.union(set('.format(class_name, all_names_map_name, parent_type_class_name) after = '))' else: before = '{}.{} = set('.format(class_name, all_names_map_name) after = ')' items = [ "'%s'" % field.name for field in data_type.fields if field.omitted_caller == omitted_caller ] self.generate_multiline_list( items, before=before, after=after, delim=('[', ']'), compact=False) # generate `_all_fields_` fields_map_name = '{}_fields_'.format(map_name_prefix) all_fields_map_name = '_all{}_fields_'.format(map_name_prefix) if data_type.is_member_of_enumerated_subtypes_tree(): items = [] for field in data_type.fields: if field.omitted_caller != omitted_caller: continue var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format(class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list( items, before='{}.{} = '.format(class_name, fields_map_name), delim=('[', ']'), compact=False, ) if caller_in_parent: self.emit('{0}.{3} = {1}.{3} + {0}.{2}'.format( class_name, parent_type_class_name, fields_map_name, all_fields_map_name)) else: self.emit('{0}.{2} = {0}.{1}'.format( class_name, fields_map_name, all_fields_map_name)) else: if caller_in_parent: before = '{0}.{2} = {1}.{2} + '.format( class_name, parent_type_class_name, all_fields_map_name) else: before = '{}.{} = '.format(class_name, all_fields_map_name) items = [] for field in data_type.fields: if field.omitted_caller != omitted_caller: continue var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list( items, before=before, delim=('[', ']'), compact=False) self.emit()
def _generate_struct_class_reflection_attributes(self, ns, data_type): """ Generates two class attributes: * _all_field_names_: Set of all field names including inherited fields. * _all_fields_: List of tuples, where each tuple is (name, validator). If a struct has enumerated subtypes, then two additional attributes are generated: * _field_names_: Set of all field names excluding inherited fields. * _fields: List of tuples, where each tuple is (name, validator), and excludes inherited fields. These are needed because serializing a struct with enumerated subtypes requires knowing the fields defined in each level of the hierarchy. """ class_name = class_name_for_data_type(data_type) if data_type.parent_type: parent_type_class_name = class_name_for_data_type( data_type.parent_type, ns) else: parent_type_class_name = None for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor( ns, field.data_type) full_validator_name = '{}._{}_validator'.format( class_name, field_name) self.emit('{} = {}'.format(full_validator_name, validator_name)) if field.redactor: self._generate_redactor(full_validator_name, field.redactor) # Generate `_all_field_names_` and `_all_fields_` for every omitted caller (and public). # As an edge case, we union omitted callers with None in the case when the object has no # public fields, as we still need to generate public attributes (`_field_names_` etc) child_omitted_callers = data_type.get_all_omitted_callers() | {None} parent_omitted_callers = data_type.parent_type.get_all_omitted_callers() if \ data_type.parent_type else set([]) for omitted_caller in child_omitted_callers | parent_omitted_callers: is_public = omitted_caller is None map_name_prefix = '' if is_public else '_{}'.format(omitted_caller) caller_in_parent = data_type.parent_type and ( is_public or omitted_caller in parent_omitted_callers) # generate `_all_field_names_` names_map_name = '{}_field_names_'.format(map_name_prefix) all_names_map_name = '_all{}_field_names_'.format(map_name_prefix) if data_type.is_member_of_enumerated_subtypes_tree(): if is_public or omitted_caller in child_omitted_callers: self.generate_multiline_list([ "'%s'" % field.name for field in data_type.fields if field.omitted_caller == omitted_caller ], before='{}.{} = set('.format( class_name, names_map_name), after=')', delim=('[', ']'), compact=False) if caller_in_parent: self.emit('{0}.{3} = {1}.{3}.union({0}.{2})'.format( class_name, parent_type_class_name, names_map_name, all_names_map_name)) else: self.emit('{0}.{2} = {0}.{1}'.format( class_name, names_map_name, all_names_map_name)) else: if caller_in_parent: before = '{0}.{1} = {2}.{1}.union(set('.format( class_name, all_names_map_name, parent_type_class_name) after = '))' else: before = '{}.{} = set('.format(class_name, all_names_map_name) after = ')' items = [ "'%s'" % field.name for field in data_type.fields if field.omitted_caller == omitted_caller ] self.generate_multiline_list(items, before=before, after=after, delim=('[', ']'), compact=False) # generate `_all_fields_` fields_map_name = '{}_fields_'.format(map_name_prefix) all_fields_map_name = '_all{}_fields_'.format(map_name_prefix) if data_type.is_member_of_enumerated_subtypes_tree(): items = [] for field in data_type.fields: if field.omitted_caller != omitted_caller: continue var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list( items, before='{}.{} = '.format(class_name, fields_map_name), delim=('[', ']'), compact=False, ) if caller_in_parent: self.emit('{0}.{3} = {1}.{3} + {0}.{2}'.format( class_name, parent_type_class_name, fields_map_name, all_fields_map_name)) else: self.emit('{0}.{2} = {0}.{1}'.format( class_name, fields_map_name, all_fields_map_name)) else: if caller_in_parent: before = '{0}.{2} = {1}.{2} + '.format( class_name, parent_type_class_name, all_fields_map_name) else: before = '{}.{} = '.format(class_name, all_fields_map_name) items = [] for field in data_type.fields: if field.omitted_caller != omitted_caller: continue var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list(items, before=before, delim=('[', ']'), compact=False) self.emit()
def _generate_struct_class_reflection_attributes(self, ns, data_type): """ Generates two class attributes: * _all_field_names_: Set of all field names including inherited fields. * _all_fields_: List of tuples, where each tuple is (name, validator). If a struct has enumerated subtypes, then two additional attributes are generated: * _field_names_: Set of all field names excluding inherited fields. * _fields: List of tuples, where each tuple is (name, validator), and excludes inherited fields. These are needed because serializing a struct with enumerated subtypes requires knowing the fields defined in each level of the hierarchy. """ class_name = class_name_for_data_type(data_type) if data_type.parent_type: parent_type_class_name = class_name_for_data_type( data_type.parent_type, ns) else: parent_type_class_name = None for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor( ns, field.data_type) self.emit('{}._{}_validator = {}'.format(class_name, field_name, validator_name)) if data_type.is_member_of_enumerated_subtypes_tree(): self.generate_multiline_list( ["'%s'" % field.name for field in data_type.fields], before='{}._field_names_ = set('.format(class_name), after=')', delim=('[', ']'), compact=False) if parent_type_class_name: self.emit( '{0}._all_field_names_ = ' '{1}._all_field_names_.union({0}._field_names_)'.format( class_name, parent_type_class_name)) else: self.emit('{0}._all_field_names_ = {0}._field_names_'.format( class_name)) else: if parent_type_class_name: before = ('{}._all_field_names_ = ' '{}._all_field_names_.union(set(').format( class_name, parent_type_class_name) after = '))' else: before = '{}._all_field_names_ = set('.format(class_name) after = ')' self.generate_multiline_list( ["'%s'" % field.name for field in data_type.fields], before=before, after=after, delim=('[', ']'), compact=False) if data_type.is_member_of_enumerated_subtypes_tree(): items = [] for field in data_type.fields: var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list( items, before='{}._fields_ = '.format(class_name), delim=('[', ']'), compact=False, ) if parent_type_class_name: self.emit('{0}._all_fields_ = ' '{1}._all_fields_ + {0}._fields_'.format( class_name, parent_type_class_name)) else: self.emit('{0}._all_fields_ = {0}._fields_'.format(class_name)) else: if parent_type_class_name: before = '{}._all_fields_ = {}._all_fields_ + '.format( class_name, parent_type_class_name) else: before = '{}._all_fields_ = '.format(class_name) items = [] for field in data_type.fields: var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list(items, before=before, delim=('[', ']'), compact=False) self.emit()
def _generate_route_helper(self, namespace, route, download_to_file=False): """Generate a Python method that corresponds to a route. :param namespace: Namespace that the route belongs to. :param bool download_to_file: Whether a special version of the route that downloads the response body to a file should be generated. This can only be used for download-style routes. """ arg_data_type = route.arg_data_type result_data_type = route.result_data_type request_binary_body = route.attrs.get('style') == 'upload' response_binary_body = route.attrs.get('style') == 'download' if download_to_file: assert response_binary_body, 'download_to_file can only be set ' \ 'for download-style routes.' self._generate_route_method_decl(namespace, route, arg_data_type, request_binary_body, method_name_suffix='_to_file', extra_args=['download_path']) else: self._generate_route_method_decl(namespace, route, arg_data_type, request_binary_body) with self.indent(): extra_request_args = None extra_return_arg = None footer = None if request_binary_body: extra_request_args = [('f', 'bytes', 'Contents to upload.')] elif download_to_file: extra_request_args = [('download_path', 'str', 'Path on local machine to save file.')] if response_binary_body and not download_to_file: extra_return_arg = ':class:`requests.models.Response`' footer = DOCSTRING_CLOSE_RESPONSE if route.doc: func_docstring = self.process_doc(route.doc, self._docf) else: func_docstring = None self._generate_docstring_for_func( namespace, arg_data_type, result_data_type, route.error_data_type, overview=func_docstring, extra_request_args=extra_request_args, extra_return_arg=extra_return_arg, footer=footer, ) self._maybe_generate_deprecation_warning(route) # Code to instantiate a class for the request data type if is_void_type(arg_data_type): self.emit('arg = None') elif is_struct_type(arg_data_type): self.generate_multiline_list( [f.name for f in arg_data_type.all_fields], before='arg = {}.{}'.format( arg_data_type.namespace.name, fmt_class(arg_data_type.name)), ) elif not is_union_type(arg_data_type): raise AssertionError('Unhandled request type %r' % arg_data_type) # Code to make the request args = [ '{}.{}'.format(namespace.name, fmt_var(route.name)), "'{}'".format(namespace.name), 'arg'] if request_binary_body: args.append('f') else: args.append('None') self.generate_multiline_list(args, 'r = self.request', compact=False) if download_to_file: self.emit('self._save_body_to_file(download_path, r[1])') if is_void_type(result_data_type): self.emit('return None') else: self.emit('return r[0]') else: if is_void_type(result_data_type): self.emit('return None') else: self.emit('return r') self.emit()
def _generate_struct_class_reflection_attributes(self, ns, data_type): """ Generates two class attributes: * _all_field_names_: Set of all field names including inherited fields. * _all_fields_: List of tuples, where each tuple is (name, validator). If a struct has enumerated subtypes, then two additional attributes are generated: * _field_names_: Set of all field names excluding inherited fields. * _fields: List of tuples, where each tuple is (name, validator), and excludes inherited fields. These are needed because serializing a struct with enumerated subtypes requires knowing the fields defined in each level of the hierarchy. """ class_name = class_name_for_data_type(data_type) if data_type.parent_type: parent_type_class_name = class_name_for_data_type( data_type.parent_type, ns) else: parent_type_class_name = None for field in data_type.fields: field_name = fmt_var(field.name) validator_name = generate_validator_constructor(ns, field.data_type) self.emit('{}._{}_validator = {}'.format( class_name, field_name, validator_name)) if data_type.is_member_of_enumerated_subtypes_tree(): self.generate_multiline_list( ["'%s'" % field.name for field in data_type.fields], before='{}._field_names_ = set('.format(class_name), after=')', delim=('[', ']'), compact=False) if parent_type_class_name: self.emit( '{0}._all_field_names_ = ' '{1}._all_field_names_.union({0}._field_names_)' .format(class_name, parent_type_class_name)) else: self.emit('{0}._all_field_names_ = {0}._field_names_'.format( class_name)) else: if parent_type_class_name: before = ( '{}._all_field_names_ = ' '{}._all_field_names_.union(set(').format( class_name, parent_type_class_name) after = '))' else: before = '{}._all_field_names_ = set('.format(class_name) after = ')' self.generate_multiline_list( ["'%s'" % field.name for field in data_type.fields], before=before, after=after, delim=('[', ']'), compact=False) if data_type.is_member_of_enumerated_subtypes_tree(): items = [] for field in data_type.fields: var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format(class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list( items, before='{}._fields_ = '.format(class_name), delim=('[', ']'), compact=False, ) if parent_type_class_name: self.emit( '{0}._all_fields_ = ' '{1}._all_fields_ + {0}._fields_'.format( class_name, parent_type_class_name)) else: self.emit('{0}._all_fields_ = {0}._fields_'.format(class_name)) else: if parent_type_class_name: before = '{}._all_fields_ = {}._all_fields_ + '.format( class_name, parent_type_class_name) else: before = '{}._all_fields_ = '.format(class_name) items = [] for field in data_type.fields: var_name = fmt_var(field.name) validator_name = '{}._{}_validator'.format( class_name, var_name) items.append("('{}', {})".format(var_name, validator_name)) self.generate_multiline_list( items, before=before, delim=('[', ']'), compact=False) self.emit()