def _generate_routes(self, route_schema, namespace): for route in namespace.routes: var_name = fmt_func(route.name) data_types = [route.arg_data_type, route.result_data_type, route.error_data_type] with self.block('%s = bb.Route(' % var_name, delim=(None, None), after=')'): self.emit("'%s'," % route.name) self.emit("%r," % (route.deprecated is not None)) for data_type in data_types: self.emit( generate_validator_constructor(namespace, data_type) + ',') attrs = [] for field in route_schema.fields: attr_key = field.name attrs.append("'%s': %r" % (attr_key, route.attrs.get(attr_key))) self.generate_multiline_list( attrs, delim=('{', '}'), after=',', compact=True) if namespace.routes: self.emit() with self.block('ROUTES =', delim=('{', '}')): for route in namespace.routes: var_name = fmt_func(route.name) self.emit("'{}': {},".format(route.name, var_name)) self.emit()
def _docf(self, tag, val): """ Callback used as the handler argument to process_docs(). This converts Babel doc references to Sphinx-friendly annotations. """ if tag == 'type': fq_val = val if '.' not in val: fq_val = self.cur_namespace.name + '.' + fq_val return ':class:`{}.{}`'.format(self.args.types_package, fq_val) elif tag == 'route': if '.' in val: return ':meth:`{}`'.format(fmt_func(val)) else: return ':meth:`{}_{}`'.format(self.cur_namespace.name, fmt_func(val)) elif tag == 'link': anchor, link = val.rsplit(' ', 1) return '`{} <{}>`_'.format(anchor, link) elif tag == 'val': if val == 'null': return 'None' elif val == 'true' or val == 'false': return '``{}``'.format(val.capitalize()) else: return val elif tag == 'field': return '``{}``'.format(val) else: raise RuntimeError('Unknown doc ref tag %r' % tag)
def _generate_routes(self, route_schema, namespace): for route in namespace.routes: var_name = fmt_func(route.name) data_types = [route.arg_data_type, route.result_data_type, route.error_data_type] with self.block('%s = bb.Route(' % var_name, delim=(None, None), after=')'): self.emit("'%s'," % route.name) self.emit("%r," % (route.deprecated is not None)) for data_type in data_types: self.emit( generate_validator_constructor(namespace, data_type) + ',') attrs = [] for field in route_schema.fields: attr_key = field.name attrs.append("'%s': %r" % (attr_key, route.attrs.get(attr_key))) self.generate_multiline_list( attrs, delim=('{', '}'), after=',', compact=True) if namespace.routes: self.emit() with self.block('ROUTES =', delim=('{', '}')): for route in namespace.routes: var_name = fmt_func(route.name) self.emit("'{}': {},".format(route.name, var_name)) self.emit()
def _generate_union_class_variant_creators(self, ns, data_type): """ Each non-symbol, non-any variant has a corresponding class method that can be used to construct a union with that variant selected. """ for field in data_type.fields: if not is_void_type(field.data_type): field_name = fmt_func(field.name) field_name_reserved_check = fmt_func(field.name, True) if is_nullable_type(field.data_type): field_dt = field.data_type.data_type else: field_dt = field.data_type self.emit('@classmethod') self.emit('def {}(cls, val):'.format(field_name_reserved_check)) with self.indent(): self.emit('"""') self.emit_wrapped_text( 'Create an instance of this class set to the ``%s`` ' 'tag with value ``val``.' % field_name) self.emit() self.emit(':param {} val:'.format( self._python_type_mapping(ns, field_dt))) self.emit(':rtype: {}'.format( fmt_class(data_type.name))) self.emit('"""') self.emit("return cls('{}', val)".format(field_name)) self.emit()
def _docf(self, tag, val): """ Callback used as the handler argument to process_docs(). This converts Babel doc references to Sphinx-friendly annotations. """ if tag == 'type': fq_val = val if '.' not in val: fq_val = self.cur_namespace.name + '.' + fq_val return ':class:`{}.{}`'.format(self.args.types_package, fq_val) elif tag == 'route': if '.' in val: return ':meth:`{}`'.format(fmt_func(val)) else: return ':meth:`{}_{}`'.format(self.cur_namespace.name, fmt_func(val)) elif tag == 'link': anchor, link = val.rsplit(' ', 1) return '`{} <{}>`_'.format(anchor, link) elif tag == 'val': if val == 'null': return 'None' elif val == 'true' or val == 'false': return '``{}``'.format(val.capitalize()) else: return val elif tag == 'field': return '``{}``'.format(val) else: raise RuntimeError('Unknown doc ref tag %r' % tag)
def _generate_union_class_variant_creators(self, ns, data_type): """ Each non-symbol, non-any variant has a corresponding class method that can be used to construct a union with that variant selected. """ for field in data_type.fields: if not is_void_type(field.data_type): field_name = fmt_func(field.name) field_name_reserved_check = fmt_func(field.name, True) if is_nullable_type(field.data_type): field_dt = field.data_type.data_type else: field_dt = field.data_type self.emit('@classmethod') self.emit('def {}(cls, val):'.format(field_name_reserved_check)) with self.indent(): self.emit('"""') self.emit_wrapped_text( 'Create an instance of this class set to the ``%s`` ' 'tag with value ``val``.' % field_name) self.emit() self.emit(':param {} val:'.format( self._python_type_mapping(ns, field_dt))) self.emit(':rtype: {}'.format( fmt_class(data_type.name))) self.emit('"""') self.emit("return cls('{}', val)".format(field_name)) self.emit()
def _docf(self, tag, val): """ Callback used as the handler argument to process_docs(). This converts Stone doc references to Sphinx-friendly annotations. """ if tag == 'type': return ':class:`{}`'.format(val) elif tag == 'route': if self.args.route_method: return ':meth:`%s`' % self.args.route_method.format( ns=self.cur_namespace.name, route=fmt_func(val)) else: return val elif tag == 'link': anchor, link = val.rsplit(' ', 1) return '`{} <{}>`_'.format(anchor, link) elif tag == 'val': if val == 'null': return 'None' elif val == 'true' or val == 'false': return '``{}``'.format(val.capitalize()) else: return val elif tag == 'field': return '``{}``'.format(val) else: raise RuntimeError('Unknown doc ref tag %r' % tag)
def _docf(self, tag, val): """ Callback used as the handler argument to process_docs(). This converts Stone doc references to Sphinx-friendly annotations. """ if tag == 'type': return ':class:`{}`'.format(val) elif tag == 'route': if self.args.route_method: return ':meth:`%s`' % self.args.route_method.format( ns=self.cur_namespace.name, route=fmt_func(val)) else: return val elif tag == 'link': anchor, link = val.rsplit(' ', 1) return '`{} <{}>`_'.format(anchor, link) elif tag == 'val': if val == 'null': return 'None' elif val == 'true' or val == 'false': return '``{}``'.format(val.capitalize()) else: return val elif tag == 'field': return '``{}``'.format(val) else: raise RuntimeError('Unknown doc ref tag %r' % tag)
def _generate_route_method_decl(self, namespace, route, arg_data_type, request_binary_body, method_name_suffix=None, extra_args=None): """Generates the method prototype for a route.""" method_name = fmt_func(route.name) namespace_name = fmt_func(namespace.name) if method_name_suffix: method_name += method_name_suffix args = ['self'] if extra_args: args += extra_args if request_binary_body: args.append('f') if is_struct_type(arg_data_type): for field in arg_data_type.all_fields: if is_nullable_type(field.data_type): args.append('{}=None'.format(field.name)) elif field.has_default: # TODO(kelkabany): Decide whether we really want to set the # default in the argument list. This will send the default # over the wire even if it isn't overridden. The benefit is # it locks in a default even if it is changed server-side. if is_user_defined_type(field.data_type): ns = field.data_type.namespace else: ns = None arg = '{}={}'.format( field.name, self._generate_python_value(ns, field.default)) args.append(arg) else: args.append(field.name) elif is_union_type(arg_data_type): args.append('arg') elif not is_void_type(arg_data_type): raise AssertionError('Unhandled request type: %r' % arg_data_type) self.generate_multiline_list( args, 'def {}_{}'.format(namespace_name, method_name), ':')
def _generate_union_class_is_set(self, data_type): for field in data_type.fields: field_name = fmt_func(field.name) self.emit('def is_{}(self):'.format(field_name)) with self.indent(): self.emit('"""') self.emit('Check if the union tag is ``%s``.' % field_name) self.emit() self.emit(':rtype: bool') self.emit('"""') self.emit("return self._tag == '{}'".format(field_name)) self.emit()
def _generate_union_class_is_set(self, data_type): for field in data_type.fields: field_name = fmt_func(field.name) self.emit('def is_{}(self):'.format(field_name)) with self.indent(): self.emit('"""') self.emit('Check if the union tag is ``%s``.' % field_name) self.emit() self.emit(':rtype: bool') self.emit('"""') self.emit("return self._tag == '{}'".format(field_name)) self.emit()
def _generate_union_class_symbol_creators(self, data_type): """ Class attributes that represent a symbol are set after the union class definition. """ class_name = fmt_class(data_type.name) lineno = self.lineno for field in data_type.fields: if is_void_type(field.data_type): field_name = fmt_func(field.name) self.emit("{0}.{1} = {0}('{1}')".format(class_name, field_name)) if lineno != self.lineno: self.emit()
def _generate_union_class_symbol_creators(self, data_type): """ Class attributes that represent a symbol are set after the union class definition. """ class_name = fmt_class(data_type.name) lineno = self.lineno for field in data_type.fields: if is_void_type(field.data_type): field_name = fmt_func(field.name) self.emit("{0}.{1} = {0}('{1}')".format(class_name, field_name)) if lineno != self.lineno: self.emit()
def _generate_route_method_decl( self, namespace, route, arg_data_type, request_binary_body, method_name_suffix=None, extra_args=None): """Generates the method prototype for a route.""" method_name = fmt_func(route.name) namespace_name = fmt_func(namespace.name) if method_name_suffix: method_name += method_name_suffix args = ['self'] if extra_args: args += extra_args if request_binary_body: args.append('f') if is_struct_type(arg_data_type): for field in arg_data_type.all_fields: if is_nullable_type(field.data_type): args.append('{}=None'.format(field.name)) elif field.has_default: # TODO(kelkabany): Decide whether we really want to set the # default in the argument list. This will send the default # over the wire even if it isn't overridden. The benefit is # it locks in a default even if it is changed server-side. if is_user_defined_type(field.data_type): ns = field.data_type.namespace else: ns = None arg = '{}={}'.format( field.name, self._generate_python_value(ns, field.default)) args.append(arg) else: args.append(field.name) elif is_union_type(arg_data_type): args.append('arg') elif not is_void_type(arg_data_type): raise AssertionError('Unhandled request type: %r' % arg_data_type) self.generate_multiline_list( args, 'def {}_{}'.format(namespace_name, method_name), ':')
def _generate_struct_class_properties(self, ns, struct): # type: (ApiNamespace, Struct) -> None to_emit = [] # type: typing.List[typing.Text] for field in struct.all_fields: field_name_reserved_check = fmt_func(field.name, check_reserved=True) field_type = self.map_stone_type_to_pep484_type(ns, field.data_type) to_emit.extend( self.property_template.format( field_name=field_name_reserved_check, field_type=field_type ).split("\n") ) for s in to_emit: self.emit(s)
def _generate_struct_class_properties(self, ns, struct): # type: (ApiNamespace, Struct) -> None to_emit = [] # type: typing.List[typing.Text] for field in struct.all_fields: field_name_reserved_check = fmt_func(field.name, check_reserved=True) field_type = self.map_stone_type_to_pep484_type( ns, field.data_type) to_emit.extend( self.property_template.format( field_name=field_name_reserved_check, field_type=field_type).split("\n")) for s in to_emit: self.emit(s)
def _generate_union_class_get_helpers(self, ns, data_type): # type: (ApiNamespace, Union) -> None """ Generates the following section in the 'union Shape' example: def get_circle(self) -> float: ... """ for field in data_type.fields: field_name = fmt_func(field.name) if not is_void_type(field.data_type): # generate getter for field val_type = self.map_stone_type_to_pep484_type(ns, field.data_type) self.emit('def get_{field_name}(self) -> {val_type}: ...'.format( field_name=field_name, val_type=val_type, )) 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) self.generate_multiline_list( [ fmt_func(f.name, True) for f in data_type.parent_type.all_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_union_class_variant_creators(self, ns, data_type): # type: (ApiNamespace, Union) -> None """ Generate the following section in the 'union Shape' example: @classmethod def circle(cls, val: float) -> Shape: ... """ union_type = class_name_for_data_type(data_type) for field in data_type.fields: if not is_void_type(field.data_type): field_name_reserved_check = fmt_func(field.name, True) val_type = self.map_stone_type_to_pep484_type(ns, field.data_type) self.emit('@classmethod') self.emit('def {field_name}(cls, val: {val_type}) -> {union_type}: ...'.format( field_name=field_name_reserved_check, val_type=val_type, union_type=union_type, )) 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) self.generate_multiline_list( [fmt_func(f.name, True) for f in data_type.parent_type.all_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_union_class_get_helpers(self, ns, data_type): """ These are the getters used to access the value of a variant, once the tag has been switched on. """ for field in data_type.fields: field_name = fmt_func(field.name) if not is_void_type(field.data_type): # generate getter for field self.emit('def get_{}(self):'.format(field_name)) with self.indent(): if is_nullable_type(field.data_type): field_dt = field.data_type.data_type else: field_dt = field.data_type self.emit('"""') if field.doc: self.emit_wrapped_text( self.process_doc(field.doc, self._docf)) self.emit() self.emit("Only call this if :meth:`is_%s` is true." % field_name) # Sphinx wants an extra line between the text and the # rtype declaration. self.emit() self.emit(':rtype: {}'.format( self._python_type_mapping(ns, field_dt))) self.emit('"""') self.emit('if not self.is_{}():'.format(field_name)) with self.indent(): self.emit( 'raise AttributeError("tag \'{}\' not set")'.format( field_name)) self.emit('return self._value') self.emit()
def _generate_union_class_get_helpers(self, ns, data_type): """ These are the getters used to access the value of a variant, once the tag has been switched on. """ for field in data_type.fields: field_name = fmt_func(field.name) if not is_void_type(field.data_type): # generate getter for field self.emit('def get_{}(self):'.format(field_name)) with self.indent(): if is_nullable_type(field.data_type): field_dt = field.data_type.data_type else: field_dt = field.data_type self.emit('"""') if field.doc: self.emit_wrapped_text( self.process_doc(field.doc, self._docf)) self.emit() self.emit("Only call this if :meth:`is_%s` is true." % field_name) # Sphinx wants an extra line between the text and the # rtype declaration. self.emit() self.emit(':rtype: {}'.format( self._python_type_mapping(ns, field_dt))) self.emit('"""') self.emit('if not self.is_{}():'.format(field_name)) with self.indent(): self.emit( 'raise AttributeError("tag \'{}\' not set")'.format( field_name)) self.emit('return self._value') self.emit()
def _generate_union_class_is_set(self, union): # type: (Union) -> None for field in union.fields: field_name = fmt_func(field.name) self.emit('def is_{}(self) -> bool: ...'.format(field_name)) self.emit()
def _generate_struct_class_properties(self, ns, data_type): """ Each field of the struct has a corresponding setter and getter. The setter validates the value being set. """ for field in data_type.fields: field_name = fmt_func(field.name) field_name_reserved_check = fmt_func(field.name, True) if is_nullable_type(field.data_type): field_dt = field.data_type.data_type dt_nullable = True else: field_dt = field.data_type dt_nullable = False # generate getter for field self.emit('@property') self.emit('def {}(self):'.format(field_name_reserved_check)) with self.indent(): self.emit('"""') if field.doc: self.emit_wrapped_text( self.process_doc(field.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, field_dt))) self.emit('"""') self.emit('if self._{}_present:'.format(field_name)) with self.indent(): self.emit('return self._{}_value'.format(field_name)) self.emit('else:') with self.indent(): if dt_nullable: self.emit('return None') elif field.has_default: self.emit('return {}'.format( self._generate_python_value(ns, field.default))) else: self.emit( "raise AttributeError(\"missing required field '%s'\")" % field_name ) self.emit() # generate setter for field self.emit('@{}.setter'.format(field_name_reserved_check)) self.emit('def {}(self, val):'.format(field_name_reserved_check)) with self.indent(): if dt_nullable: self.emit('if val is None:') with self.indent(): self.emit('del self.{}'.format(field_name_reserved_check)) self.emit('return') if is_user_defined_type(field_dt): self.emit('self._%s_validator.validate_type_only(val)' % field_name) else: self.emit('val = self._{}_validator.validate(val)'.format(field_name)) self.emit('self._{}_value = val'.format(field_name)) self.emit('self._{}_present = True'.format(field_name)) self.emit() # generate deleter for field self.emit('@{}.deleter'.format(field_name_reserved_check)) self.emit('def {}(self):'.format(field_name_reserved_check)) with self.indent(): self.emit('self._{}_value = None'.format(field_name)) self.emit('self._{}_present = False'.format(field_name)) self.emit()
def _generate_union_class_is_set(self, union): # type: (Union) -> None for field in union.fields: field_name = fmt_func(field.name) self.emit('def is_{}(self) -> bool: ...'.format(field_name)) self.emit()
def _generate_struct_class_properties(self, ns, data_type): """ Each field of the struct has a corresponding setter and getter. The setter validates the value being set. """ for field in data_type.fields: field_name = fmt_func(field.name) field_name_reserved_check = fmt_func(field.name, True) if is_nullable_type(field.data_type): field_dt = field.data_type.data_type dt_nullable = True else: field_dt = field.data_type dt_nullable = False # generate getter for field self.emit('@property') self.emit('def {}(self):'.format(field_name_reserved_check)) with self.indent(): self.emit('"""') if field.doc: self.emit_wrapped_text( self.process_doc(field.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, field_dt))) self.emit('"""') self.emit('if self._{}_present:'.format(field_name)) with self.indent(): self.emit('return self._{}_value'.format(field_name)) self.emit('else:') with self.indent(): if dt_nullable: self.emit('return None') elif field.has_default: self.emit('return {}'.format( self._generate_python_value(ns, field.default))) else: self.emit( "raise AttributeError(\"missing required field '%s'\")" % field_name ) self.emit() # generate setter for field self.emit('@{}.setter'.format(field_name_reserved_check)) self.emit('def {}(self, val):'.format(field_name_reserved_check)) with self.indent(): if dt_nullable: self.emit('if val is None:') with self.indent(): self.emit('del self.{}'.format(field_name_reserved_check)) self.emit('return') if is_user_defined_type(field_dt): self.emit('self._%s_validator.validate_type_only(val)' % field_name) else: self.emit('val = self._{}_validator.validate(val)'.format(field_name)) self.emit('self._{}_value = val'.format(field_name)) self.emit('self._{}_present = True'.format(field_name)) self.emit() # generate deleter for field self.emit('@{}.deleter'.format(field_name_reserved_check)) self.emit('def {}(self):'.format(field_name_reserved_check)) with self.indent(): self.emit('self._{}_value = None'.format(field_name)) self.emit('self._{}_present = False'.format(field_name)) self.emit()