just run ``Tools/clinic/clinic.py --converters`` for the full list.
+Cloning existing functions
+--------------------------
+
+If you have a number of functions that look similar, you may be able to
+use Clinic's "clone" feature. When you clone an existing function,
+you reuse:
+
+* its parameters, including
+
+ * their names,
+
+ * their converters, with all parameters,
+
+ * their default values,
+
+ * their per-parameter docstrings,
+
+ * their *kind* (whether they're positional only,
+ positional or keyword, or keyword only), and
+
+* its return converter.
+
+The only thing not copied from the original function is its docstring;
+the syntax allows you to specify a new docstring.
+
+Here's the syntax for cloning a function::
+
+ /*[clinic input]
+ module.class.new_function [as c_basename] = module.class.existing_function
+
+ Docstring for new_function goes here.
+ [clinic start generated code]*/
+
+(The functions can be in different modules or classes. I wrote
+``module.class`` in the sample just to illustrate that you must
+use the full path to *both* functions.)
+
+Sorry, there's no syntax for partially-cloning a function, or cloning a function
+then modifying it. Cloning is an all-or nothing proposition.
+
+Also, the function you are cloning from must have been previously defined
+in the current file.
+
Calling Python code
-------------------
# modulename.fnname [as c_basename] [-> return annotation]
# square brackets denote optional syntax.
#
+ # alternatively:
+ # modulename.fnname [as c_basename] = modulename.existing_fn_name
+ # clones the parameters and return converter from that
+ # function. you can't modify them. you must enter a
+ # new docstring.
+ #
# (but we might find a directive first!)
#
# this line is permitted to start with whitespace.
directive(*fields[1:])
return
+ # are we cloning?
+ before, equals, existing = line.rpartition('=')
+ if equals:
+ full_name, _, c_basename = before.partition(' as ')
+ full_name = full_name.strip()
+ c_basename = c_basename.strip()
+ existing = existing.strip()
+ if (is_legal_py_identifier(full_name) and
+ (not c_basename or is_legal_c_identifier(c_basename)) and
+ is_legal_py_identifier(existing)):
+ # we're cloning!
+ fields = [x.strip() for x in existing.split('.')]
+ function_name = fields.pop()
+ module, cls = self.clinic._module_and_class(fields)
+
+ for existing_function in (cls or module).functions:
+ if existing_function.name == function_name:
+ break
+ else:
+ existing_function = None
+ if not existing_function:
+ fail("Couldn't find existing function " + repr(existing) + "!")
+
+ fields = [x.strip() for x in full_name.split('.')]
+ function_name = fields.pop()
+ module, cls = self.clinic._module_and_class(fields)
+
+ if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist):
+ fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)")
+ self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
+ return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist)
+
+ self.function.parameters = existing_function.parameters.copy()
+
+ self.block.signatures.append(self.function)
+ (cls or module).functions.append(self.function)
+ self.next(self.state_function_docstring)
+ return
+
line, _, returns = line.partition('->')
full_name, _, c_basename = line.partition(' as ')
self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,
return_converter=return_converter, kind=self.kind, coexist=self.coexist)
self.block.signatures.append(self.function)
+ (cls or module).functions.append(self.function)
self.next(self.state_parameters_start)
# Now entering the parameters section. The rules, formally stated: