parameters: (func)
return_statement: return func
docstring: Decorator that applies docstring templates to function docstring
      and returns the function instance.
docstring_summary: Decorator that applies docstring templates to function docstring
      and returns the function instance.
docstring_tokens: Decorator that applies docstring templates to function docstring and returns the function instance .
function: def _apply_docstring_templates(func):
      """Decorator that applies docstring templates to function docstring
      and returns the function instance.
      """
      docstring_templates = dict(
          reduction_signature='''\
  {function_name}(input, {operation_args}, *, {operation_kwargs}) -> Tensor''',
          reduction_descr='''\
  Returns {operation name} of all the elements in the :attr:`input`
  tensor along the given dimension(s) :attr:`dim` while the :attr:`input`
  elements are masked out according to the boolean tensor
  :attr:`mask`.''',
          reduction_args='''\
  If :attr:`keepdim` is ``True``, the output tensor is of the same size
  as :attr:`input` except in the dimension(s) :attr:`dim` where it is of
  size 1. Otherwise, :attr:`dim` is squeezed (see
  :func:`torch.squeeze`), resulting in the output tensor having 1 (or
  ``len(dim)``) fewer dimension(s).
  
  The boolean tensor :attr:`mask` defines the "validity" of
  :attr:`input` tensor elements: if :attr:`mask` element is True
  then the corresponding element in :attr:`input` tensor will be
  included in {operation name} computation, otherwise the element is
  ignored.
  
  When all elements of :attr:`input` along the given dimension
  :attr:`dim` are ignored (fully masked-out), the corresponding element
  of the output tensor will have undefined value: it may or may not
  correspond to the identity value of {operation name} operation; the
  choice may correspond to the value that leads to the most efficient
  storage of :attr:`output` tensor.
  
  The mask of the output tensor can be computed as
  ``torch.any(torch.broadcast_to(mask, input.shape), dim, keepdim=keepdim,
  dtype=torch.bool)``.
  
  The shapes of the :attr:`mask` tensor and the :attr:`input` tensor
  don't need to match, but they must be :ref:`broadcastable
  <broadcasting-semantics>` and the dimensionality of the :attr:`mask`
  tensor must not be greater than of the :attr:`input` tensor.
  
  Args:
      input (Tensor): the input tensor
      {args_declarations}
  
  Keyword args:
      {kwargs_declarations}''',
          reduction_example='''\
  Example::
  
      >>> input = {example_input}
      >>> input
      {indent_example_input}
      >>> mask = {example_mask}
      >>> mask
      {indent_example_mask}
      >>> {full_function_name}(input, {example_args}, mask=mask)
      {indent_example_output}
  ''',
          reduction_identity='''\
  The identity value of {operation name} operation, which is used to start the reduction, is ``{identity_int32}``.''',
          reduction_identity_dtype='''\
  The identity value of {operation name} operation, which is used to start the
  reduction, depends on input dtype. For instance, for float32, uint8,
  and int32 dtypes, the identity values are ``{identity_float32}``, ``{identity_uint8}``, and ``{identity_int32}``, respectively.''',
          normalization_signature='''\
  {function_name}(input, {operation_args}, *, {operation_kwargs}) -> Tensor''',
          normalization_descr='''\
  Returns {operation name} of all the slices in the :attr:`input` tensor
  along :attr:`dim` while the :attr:`input` elements are masked out
  according to the boolean tensor :attr:`mask`.
  
  {definition}''',
          normalization_args='''\
  The boolean tensor :attr:`mask` defines the "validity" of
  :attr:`input` tensor elements: if :attr:`mask` element is True then
  the corresponding element in :attr:`input` tensor will be included in
  {operation name} computation, otherwise the element is ignored.
  
  The values of masked-out elements of the output tensor have undefined
  value: it may or may not be set to zero or nan; the choice may correspond to
  the value that leads to the most efficient storage of :attr:`output`
  tensor.
  
  The mask of the {operation name} output tensor can be computed as
  ``torch.broadcast_to(mask, input.shape)``.
  
  The shapes of the :attr:`mask` tensor and the :attr:`input` tensor
  don't need to match, but they must be :ref:`broadcastable
  <broadcasting-semantics>` and the dimensionality of the :attr:`mask`
  tensor must not be greater than of the :attr:`input` tensor.
  
  Args:
      input (Tensor): the input tensor
      {args_declarations}
  
  Keyword args:
      {kwargs_declarations}''',
          normalization_example='''\
  Example::
  
      >>> input = {example_input}
      >>> input
      {indent_example_input}
      >>> mask = {example_mask}
      >>> mask
      {indent_example_mask}
      >>> {full_function_name}(input, {example_args}, mask=mask)
      {indent_example_output}
  ''')
  
      args_and_kwargs = dict(
          # argument name sufficies separated by double underscore will
          # be removed in the final documentation string.
          sum=(('dim',), ('keepdim=False', 'dtype=None', 'mask=None')),
          prod=(('dim',), ('keepdim=False', 'dtype=None', 'mask=None')),
          amin=(('dim',), ('keepdim=False', 'dtype=None', 'mask=None')),
          amax=(('dim',), ('keepdim=False', 'dtype=None', 'mask=None')),
          mean=(('dim',), ('keepdim=False', 'dtype=None', 'mask=None')),
          norm=(('ord', 'dim',), ('keepdim=False', 'dtype=None', 'mask=None')),
          var=(('dim', 'unbiased'), ('keepdim=False', 'dtype=None', 'mask=None')),
          softmax=(('dim__as_int',), ('dtype=None', 'mask=None')),
          log_softmax=(('dim__as_int',), ('dtype=None', 'mask=None')),
          softmin=(('dim__as_int',), ('dtype=None', 'mask=None')),
          normalize=(('ord__required', 'dim__as_int',), ('eps=1e-12', 'dtype=None', 'mask=None')),
      )
  
      argument_declarations = dict(
          dim='''\
  dim (int or tuple of ints, optional): the dimension or dimensions to reduce.
    Default: None that is equivalent to ``tuple(range(input.ndim))``.''',
          dim__as_int='''\
  dim (int): the dimension along which {operation name} is computed.''',
          ord='''\
  ord (int, float, optional): the order of vector norm. Default: 2.
    See :func:`torch.linalg.vector_norm` for a list of supported norms.''',
          ord__required='''\
  ord (int, float): the order of vector norm. Default: 2.
    See :func:`torch.linalg.vector_norm` for a list of supported norms.''',
          unbiased='''\
  unbiased (bool): when True, use Bessel’s correction, otherwise, compute
    the uncorrected sample variance.''',
          eps='''\
  eps (float, optional): small value to avoid division by zero. Default: {default}.''',
          keepdim='''\
  keepdim (bool, optional): whether the output tensor has
    :attr:`dim` retained or not. Default: {default}.''',
          dtype='''\
  dtype (:class:`torch.dtype`, optional): the desired data type
    of returned tensor.  If specified, the input tensor is
    casted to :attr:`dtype` before the operation is
    performed. Default: {default}.''',
          mask='''\
  mask (:class:`torch.Tensor`, optional): the boolean tensor
    containing the binary mask of validity of input tensor
    elements.
    Default: None that is equivalent to ``torch.ones(input.shape, dtype=torch.bool)``.''')
  
      definitions = dict(
          softmax='''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. Softmax of i-th element in ``x`` is
  defined as ``exp(x[i])/sum(exp(x))``.''',
          log_softmax='''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. LogSoftmax of i-th element in ``x`` is
  defined as ``log(exp(x[i])/sum(exp(x)))``.''',
          softmin='''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. Softmin of i-th element in ``x`` is
  defined as ``exp(-x[i])/sum(exp(-x))``.''',
          normalize='''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. Normalize of i-th element in ``x`` is
  defined as ``x[i]/max(norm(x, p), eps)``.''')
  
      reduction_names = dict(
          sum='sum',
          prod='product',
          amax='maximum',
          amin='minimum',
          mean='mean',
          norm='norm',
          var='variance')
  
      normalization_names = dict(
          softmax='softmax',
          log_softmax='log_softmax',
          softmin='softmin',
          normalize='normalize')
  
      operation_names = dict()
      operation_names.update(reduction_names)
      operation_names.update(normalization_names)
  
      # Default example data:
      example_dim = 1
      example_input = torch.tensor([[-3, -2, -1], [0, 1, 2]])
      example_mask = torch.tensor([[True, False, True], [False, False, False]])
      example_args: Tuple[Any, ...]
      if func.__name__ in {'norm', 'normalize'}:
          example_args = (2.0, example_dim)
          example_input = example_input.to(dtype=torch.float32)
      elif func.__name__ in {'var'}:
          example_args = (example_dim, False)
      else:
          example_args = (example_dim,)
  
      operation_args: Tuple[str, ...]
      operation_kwargs: Tuple[str, ...]
      operation_args, operation_kwargs = args_and_kwargs[func.__name__]
      arg_declarations = [
          '\n    '.join(argument_declarations
                        .get(a, f'{a.split("__", 1)[0]}: TBD.')
                        .splitlines())
          for a in operation_args]
      kwarg_declarations = [
          '\n    '.join(argument_declarations
                        .get(a.split('=', 1)[0], f'{a.split("__", 1)[0]}: TBD.')
                        .format(default=a.split('=', 1)[1])
                        .splitlines())
          for a in operation_kwargs]
  
      if func.__name__ in reduction_names:
          op_kind = 'reduction'
          doc_sections = ['signature', 'descr', 'identity', 'args', 'example']
      elif func.__name__ in normalization_names:
          op_kind = 'normalization'
          doc_sections = ['signature', 'descr', 'args', 'example']
          example_input = example_input.to(dtype=torch.float32)
      else:
          assert 0  # add function name to operation names dictionaries
      example_output = func(example_input, *example_args, mask=example_mask)
  
      template_data = {'function_name': func.__name__,
                       'full_function_name': func.__module__ + '.' + func.__name__,
                       'operation name': operation_names[func.__name__],
                       'operation_args': ', '.join(a.split('__', 1)[0] for a in operation_args),
                       'operation_kwargs': ', '.join(a.split('__', 1)[0] for a in operation_kwargs),
                       # one-line representation of a tensor:
                       'example_input': ' '.join(str(example_input).split()),
                       'example_args': ', '.join(map(str, example_args)),
                       'example_mask': ' '.join(str(example_mask).split()),
                       # multi-line representation of a tensor with indent
                       'indent_example_input': ('\n    ').join(str(example_input).splitlines()),
                       'indent_example_mask': ('\n    ').join(str(example_mask).splitlines()),
                       'indent_example_output': ('\n    ').join(str(example_output).splitlines())}
  
      if func.__name__ in reduction_names:
          template_data.update(
              identity_uint8=_reduction_identity(func.__name__, torch.tensor(0, dtype=torch.uint8)),
              identity_int32=_reduction_identity(func.__name__, torch.tensor(0, dtype=torch.int32)),
              identity_float32=_reduction_identity(func.__name__, torch.tensor(0, dtype=torch.float32)))
          if func.__name__ == 'norm':
              template_data.update(
                  identity_ord_ninf=_reduction_identity(
                      func.__name__, torch.tensor(0, dtype=torch.float32), float('-inf')))
      elif func.__name__ in normalization_names:
          template_data.update(definition=definitions[func.__name__])
      else:
          assert 0  # add function name to operation names dictionaries
      template_data.update(args_declarations=('\n    '.join(arg_declarations)).format_map(template_data))
      template_data.update(kwargs_declarations=('\n    '.join(kwarg_declarations)).format_map(template_data))
  
      # Apply function name info to docstring templates:
      templates = dict((k, v.format_map(template_data))
                       for k, v in docstring_templates.items() if k.startswith(op_kind))
      templates.update((k, v.format_map(template_data) if isinstance(v, str) else v) for k, v in template_data.items())
  
      # Apply docstring templates to function doctring:
      if func.__doc__ is None:
          doc_template = '\n\n'.join([f'{{{op_kind}_{sec}}}' for sec in doc_sections])
      else:
          doc_template = func.__doc__
      func.__doc__ = doc_template.format_map(templates)
  
      # Expose function as public symbol
      __all__.append(func.__name__)
  
      return func
function_tokens: def _apply_docstring_templates ( func ) : docstring_templates = dict ( reduction_signature = '''\
  {function_name}(input, {operation_args}, *, {operation_kwargs}) -> Tensor''' , reduction_descr = '''\
  Returns {operation name} of all the elements in the :attr:`input`
  tensor along the given dimension(s) :attr:`dim` while the :attr:`input`
  elements are masked out according to the boolean tensor
  :attr:`mask`.''' , reduction_args = '''\
  If :attr:`keepdim` is ``True``, the output tensor is of the same size
  as :attr:`input` except in the dimension(s) :attr:`dim` where it is of
  size 1. Otherwise, :attr:`dim` is squeezed (see
  :func:`torch.squeeze`), resulting in the output tensor having 1 (or
  ``len(dim)``) fewer dimension(s).
  
  The boolean tensor :attr:`mask` defines the "validity" of
  :attr:`input` tensor elements: if :attr:`mask` element is True
  then the corresponding element in :attr:`input` tensor will be
  included in {operation name} computation, otherwise the element is
  ignored.
  
  When all elements of :attr:`input` along the given dimension
  :attr:`dim` are ignored (fully masked-out), the corresponding element
  of the output tensor will have undefined value: it may or may not
  correspond to the identity value of {operation name} operation; the
  choice may correspond to the value that leads to the most efficient
  storage of :attr:`output` tensor.
  
  The mask of the output tensor can be computed as
  ``torch.any(torch.broadcast_to(mask, input.shape), dim, keepdim=keepdim,
  dtype=torch.bool)``.
  
  The shapes of the :attr:`mask` tensor and the :attr:`input` tensor
  don't need to match, but they must be :ref:`broadcastable
  <broadcasting-semantics>` and the dimensionality of the :attr:`mask`
  tensor must not be greater than of the :attr:`input` tensor.
  
  Args:
      input (Tensor): the input tensor
      {args_declarations}
  
  Keyword args:
      {kwargs_declarations}''' , reduction_example = '''\
  Example::
  
      >>> input = {example_input}
      >>> input
      {indent_example_input}
      >>> mask = {example_mask}
      >>> mask
      {indent_example_mask}
      >>> {full_function_name}(input, {example_args}, mask=mask)
      {indent_example_output}
  ''' , reduction_identity = '''\
  The identity value of {operation name} operation, which is used to start the reduction, is ``{identity_int32}``.''' , reduction_identity_dtype = '''\
  The identity value of {operation name} operation, which is used to start the
  reduction, depends on input dtype. For instance, for float32, uint8,
  and int32 dtypes, the identity values are ``{identity_float32}``, ``{identity_uint8}``, and ``{identity_int32}``, respectively.''' , normalization_signature = '''\
  {function_name}(input, {operation_args}, *, {operation_kwargs}) -> Tensor''' , normalization_descr = '''\
  Returns {operation name} of all the slices in the :attr:`input` tensor
  along :attr:`dim` while the :attr:`input` elements are masked out
  according to the boolean tensor :attr:`mask`.
  
  {definition}''' , normalization_args = '''\
  The boolean tensor :attr:`mask` defines the "validity" of
  :attr:`input` tensor elements: if :attr:`mask` element is True then
  the corresponding element in :attr:`input` tensor will be included in
  {operation name} computation, otherwise the element is ignored.
  
  The values of masked-out elements of the output tensor have undefined
  value: it may or may not be set to zero or nan; the choice may correspond to
  the value that leads to the most efficient storage of :attr:`output`
  tensor.
  
  The mask of the {operation name} output tensor can be computed as
  ``torch.broadcast_to(mask, input.shape)``.
  
  The shapes of the :attr:`mask` tensor and the :attr:`input` tensor
  don't need to match, but they must be :ref:`broadcastable
  <broadcasting-semantics>` and the dimensionality of the :attr:`mask`
  tensor must not be greater than of the :attr:`input` tensor.
  
  Args:
      input (Tensor): the input tensor
      {args_declarations}
  
  Keyword args:
      {kwargs_declarations}''' , normalization_example = '''\
  Example::
  
      >>> input = {example_input}
      >>> input
      {indent_example_input}
      >>> mask = {example_mask}
      >>> mask
      {indent_example_mask}
      >>> {full_function_name}(input, {example_args}, mask=mask)
      {indent_example_output}
  ''' ) args_and_kwargs = dict ( # argument name sufficies separated by double underscore will # be removed in the final documentation string. sum = ( ( 'dim' , ) , ( 'keepdim=False' , 'dtype=None' , 'mask=None' ) ) , prod = ( ( 'dim' , ) , ( 'keepdim=False' , 'dtype=None' , 'mask=None' ) ) , amin = ( ( 'dim' , ) , ( 'keepdim=False' , 'dtype=None' , 'mask=None' ) ) , amax = ( ( 'dim' , ) , ( 'keepdim=False' , 'dtype=None' , 'mask=None' ) ) , mean = ( ( 'dim' , ) , ( 'keepdim=False' , 'dtype=None' , 'mask=None' ) ) , norm = ( ( 'ord' , 'dim' , ) , ( 'keepdim=False' , 'dtype=None' , 'mask=None' ) ) , var = ( ( 'dim' , 'unbiased' ) , ( 'keepdim=False' , 'dtype=None' , 'mask=None' ) ) , softmax = ( ( 'dim__as_int' , ) , ( 'dtype=None' , 'mask=None' ) ) , log_softmax = ( ( 'dim__as_int' , ) , ( 'dtype=None' , 'mask=None' ) ) , softmin = ( ( 'dim__as_int' , ) , ( 'dtype=None' , 'mask=None' ) ) , normalize = ( ( 'ord__required' , 'dim__as_int' , ) , ( 'eps=1e-12' , 'dtype=None' , 'mask=None' ) ) , ) argument_declarations = dict ( dim = '''\
  dim (int or tuple of ints, optional): the dimension or dimensions to reduce.
    Default: None that is equivalent to ``tuple(range(input.ndim))``.''' , dim__as_int = '''\
  dim (int): the dimension along which {operation name} is computed.''' , ord = '''\
  ord (int, float, optional): the order of vector norm. Default: 2.
    See :func:`torch.linalg.vector_norm` for a list of supported norms.''' , ord__required = '''\
  ord (int, float): the order of vector norm. Default: 2.
    See :func:`torch.linalg.vector_norm` for a list of supported norms.''' , unbiased = '''\
  unbiased (bool): when True, use Bessel’s correction, otherwise, compute
    the uncorrected sample variance.''' , eps = '''\
  eps (float, optional): small value to avoid division by zero. Default: {default}.''' , keepdim = '''\
  keepdim (bool, optional): whether the output tensor has
    :attr:`dim` retained or not. Default: {default}.''' , dtype = '''\
  dtype (:class:`torch.dtype`, optional): the desired data type
    of returned tensor.  If specified, the input tensor is
    casted to :attr:`dtype` before the operation is
    performed. Default: {default}.''' , mask = '''\
  mask (:class:`torch.Tensor`, optional): the boolean tensor
    containing the binary mask of validity of input tensor
    elements.
    Default: None that is equivalent to ``torch.ones(input.shape, dtype=torch.bool)``.''' ) definitions = dict ( softmax = '''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. Softmax of i-th element in ``x`` is
  defined as ``exp(x[i])/sum(exp(x))``.''' , log_softmax = '''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. LogSoftmax of i-th element in ``x`` is
  defined as ``log(exp(x[i])/sum(exp(x)))``.''' , softmin = '''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. Softmin of i-th element in ``x`` is
  defined as ``exp(-x[i])/sum(exp(-x))``.''' , normalize = '''\
  Let ``x`` be a sequence of unmasked elements of one-dimensional slice
  of the :attr:`input` tensor. Normalize of i-th element in ``x`` is
  defined as ``x[i]/max(norm(x, p), eps)``.''' ) reduction_names = dict ( sum = 'sum' , prod = 'product' , amax = 'maximum' , amin = 'minimum' , mean = 'mean' , norm = 'norm' , var = 'variance' ) normalization_names = dict ( softmax = 'softmax' , log_softmax = 'log_softmax' , softmin = 'softmin' , normalize = 'normalize' ) operation_names = dict ( ) operation_names . update ( reduction_names ) operation_names . update ( normalization_names ) # Default example data: example_dim = 1 example_input = torch . tensor ( [ [ - 3 , - 2 , - 1 ] , [ 0 , 1 , 2 ] ] ) example_mask = torch . tensor ( [ [ True , False , True ] , [ False , False , False ] ] ) example_args : Tuple [ Any , ... ] if func . __name__ in { 'norm' , 'normalize' } : example_args = ( 2.0 , example_dim ) example_input = example_input . to ( dtype = torch . float32 ) elif func . __name__ in { 'var' } : example_args = ( example_dim , False ) else : example_args = ( example_dim , ) operation_args : Tuple [ str , ... ] operation_kwargs : Tuple [ str , ... ] operation_args , operation_kwargs = args_and_kwargs [ func . __name__ ] arg_declarations = [ '\n    ' . join ( argument_declarations . get ( a , f'{a.split("__", 1)[0]}: TBD.' ) . splitlines ( ) ) for a in operation_args ] kwarg_declarations = [ '\n    ' . join ( argument_declarations . get ( a . split ( '=' , 1 ) [ 0 ] , f'{a.split("__", 1)[0]}: TBD.' ) . format ( default = a . split ( '=' , 1 ) [ 1 ] ) . splitlines ( ) ) for a in operation_kwargs ] if func . __name__ in reduction_names : op_kind = 'reduction' doc_sections = [ 'signature' , 'descr' , 'identity' , 'args' , 'example' ] elif func . __name__ in normalization_names : op_kind = 'normalization' doc_sections = [ 'signature' , 'descr' , 'args' , 'example' ] example_input = example_input . to ( dtype = torch . float32 ) else : assert 0 # add function name to operation names dictionaries example_output = func ( example_input , * example_args , mask = example_mask ) template_data = { 'function_name' : func . __name__ , 'full_function_name' : func . __module__ + '.' + func . __name__ , 'operation name' : operation_names [ func . __name__ ] , 'operation_args' : ', ' . join ( a . split ( '__' , 1 ) [ 0 ] for a in operation_args ) , 'operation_kwargs' : ', ' . join ( a . split ( '__' , 1 ) [ 0 ] for a in operation_kwargs ) , # one-line representation of a tensor: 'example_input' : ' ' . join ( str ( example_input ) . split ( ) ) , 'example_args' : ', ' . join ( map ( str , example_args ) ) , 'example_mask' : ' ' . join ( str ( example_mask ) . split ( ) ) , # multi-line representation of a tensor with indent 'indent_example_input' : ( '\n    ' ) . join ( str ( example_input ) . splitlines ( ) ) , 'indent_example_mask' : ( '\n    ' ) . join ( str ( example_mask ) . splitlines ( ) ) , 'indent_example_output' : ( '\n    ' ) . join ( str ( example_output ) . splitlines ( ) ) } if func . __name__ in reduction_names : template_data . update ( identity_uint8 = _reduction_identity ( func . __name__ , torch . tensor ( 0 , dtype = torch . uint8 ) ) , identity_int32 = _reduction_identity ( func . __name__ , torch . tensor ( 0 , dtype = torch . int32 ) ) , identity_float32 = _reduction_identity ( func . __name__ , torch . tensor ( 0 , dtype = torch . float32 ) ) ) if func . __name__ == 'norm' : template_data . update ( identity_ord_ninf = _reduction_identity ( func . __name__ , torch . tensor ( 0 , dtype = torch . float32 ) , float ( '-inf' ) ) ) elif func . __name__ in normalization_names : template_data . update ( definition = definitions [ func . __name__ ] ) else : assert 0 # add function name to operation names dictionaries template_data . update ( args_declarations = ( '\n    ' . join ( arg_declarations ) ) . format_map ( template_data ) ) template_data . update ( kwargs_declarations = ( '\n    ' . join ( kwarg_declarations ) ) . format_map ( template_data ) ) # Apply function name info to docstring templates: templates = dict ( ( k , v . format_map ( template_data ) ) for k , v in docstring_templates . items ( ) if k . startswith ( op_kind ) ) templates . update ( ( k , v . format_map ( template_data ) if isinstance ( v , str ) else v ) for k , v in template_data . items ( ) ) # Apply docstring templates to function doctring: if func . __doc__ is None : doc_template = '\n\n' . join ( [ f'{{{op_kind}_{sec}}}' for sec in doc_sections ] ) else : doc_template = func . __doc__ func . __doc__ = doc_template . format_map ( templates ) # Expose function as public symbol __all__ . append ( func . __name__ ) return func