cython-devel
changeset 1157:075511424c24
Automatic embedding of signatures in docstring (#2)
| author | LisandroDalcin |
|---|---|
| date | Fri Sep 19 16:28:36 2008 +0200 (3 years ago) |
| parents | 02eb1bab8afa |
| children | 137cca05a493 |
| files | Cython/Compiler/AutoDocTransforms.py Cython/Compiler/Main.py Cython/Compiler/Options.py Tools/cython-epydoc.py tests/run/embedsignatures.pyx |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/Cython/Compiler/AutoDocTransforms.py Fri Sep 19 16:28:36 2008 +0200
1.3 @@ -0,0 +1,132 @@
1.4 +import re
1.5 +
1.6 +from Cython.Compiler.Visitor import CythonTransform
1.7 +from Cython.Compiler.Nodes import DefNode, CFuncDefNode
1.8 +from Cython.Compiler.Errors import CompileError
1.9 +from Cython.Compiler.StringEncoding import EncodedString
1.10 +from Cython.Compiler import Options
1.11 +
1.12 +
1.13 +class EmbedSignature(CythonTransform):
1.14 +
1.15 + SPECIAL_METHOD_RE = re.compile(r'__\w+__')
1.16 +
1.17 + def __init__(self, context):
1.18 + super(EmbedSignature, self).__init__(context)
1.19 + self.denv = None # XXX
1.20 + self.is_in_class = False
1.21 + self.class_name = None
1.22 +
1.23 + def _fmt_arg_type(self, arg):
1.24 + try:
1.25 + return arg.base_type.name
1.26 + except AttributeError:
1.27 + return ""
1.28 +
1.29 + def _fmt_arg_name(self, arg):
1.30 + try:
1.31 + return arg.declarator.name
1.32 + except AttributeError:
1.33 + return arg.declarator.base.name
1.34 +
1.35 + def _fmt_arg_defv(self, arg):
1.36 + if not arg.default:
1.37 + return None
1.38 + try:
1.39 + denv = self.denv # XXX
1.40 + ctval = arg.default.compile_time_value(self.denv)
1.41 + return '%s' % ctval
1.42 + except Exception:
1.43 + try:
1.44 + return arg.default.name # XXX
1.45 + except AttributeError:
1.46 + return '<???>'
1.47 +
1.48 + def _fmt_arg(self, arg):
1.49 + arg_type = self._fmt_arg_type(arg)
1.50 + arg_name = self._fmt_arg_name(arg)
1.51 + arg_defv = self._fmt_arg_defv(arg)
1.52 + doc = arg_name
1.53 + if arg_type:
1.54 + doc = ('%s ' % arg_type) + doc
1.55 + if arg_defv:
1.56 + doc = doc + ('=%s' % arg_defv)
1.57 + return doc
1.58 +
1.59 + def _fmt_arglist(self, args,
1.60 + npargs=0, pargs=None,
1.61 + nkargs=0, kargs=None):
1.62 + arglist = []
1.63 + for arg in args:
1.64 + arg_doc = self._fmt_arg(arg)
1.65 + arglist.append(arg_doc)
1.66 + if pargs:
1.67 + arglist.insert(npargs, '*%s' % pargs.name)
1.68 + elif nkargs:
1.69 + arglist.insert(npargs, '*')
1.70 + if kargs:
1.71 + arglist.append('**%s' % kargs.name)
1.72 + return arglist
1.73 +
1.74 + def _fmt_signature(self, cls_name, func_name, args,
1.75 + npargs=0, pargs=None,
1.76 + nkargs=0, kargs=None,
1.77 + return_type=None):
1.78 + arglist = self._fmt_arglist(args,
1.79 + npargs, pargs,
1.80 + nkargs, kargs)
1.81 + arglist = ', '.join(arglist)
1.82 + func_doc = '%s(%s)' % (func_name, arglist)
1.83 + if cls_name:
1.84 + func_doc = ('%s.' % cls_name) + func_doc
1.85 + if return_type:
1.86 + func_doc = func_doc + ' -> %s' % return_type
1.87 + return func_doc
1.88 +
1.89 + def _embed_signature(self, signature, node_doc):
1.90 + if node_doc:
1.91 + return signature + '\n' + node_doc
1.92 + else:
1.93 + return signature
1.94 +
1.95 + def visit_ClassDefNode(self, node):
1.96 + oldincls = self.is_in_class
1.97 + oldname = self.class_name
1.98 + self.is_in_class = True
1.99 + try:
1.100 + # PyClassDefNode
1.101 + self.class_name = node.name
1.102 + except AttributeError:
1.103 + # CClassDefNode
1.104 + self.class_name = node.class_name
1.105 + self.visitchildren(node)
1.106 + self.is_in_class = oldincls
1.107 + self.class_name = oldname
1.108 + return node
1.109 +
1.110 + def visit_FuncDefNode(self, node):
1.111 + signature = None
1.112 + if type(node) is DefNode: # def FOO(...):
1.113 + special_method = (self.is_in_class and \
1.114 + self.SPECIAL_METHOD_RE.match(node.name))
1.115 + if not special_method:
1.116 + nkargs = getattr(node, 'num_kwonly_args', 0)
1.117 + npargs = len(node.args) - nkargs
1.118 + signature = self._fmt_signature(
1.119 + self.class_name, node.name, node.args,
1.120 + npargs, node.star_arg,
1.121 + nkargs, node.starstar_arg,
1.122 + return_type=None)
1.123 + elif type(node) is CFuncDefNode:
1.124 + if node.overridable: # cpdef FOO(...):
1.125 + signature = self._fmt_signature(
1.126 + self.class_name, node.declarator.base.name,
1.127 + node.declarator.args,
1.128 + return_type=node.base_type.name)
1.129 + else: # should not fall here ...
1.130 + assert False
1.131 + if signature:
1.132 + if Options.docstrings and node.options['embedsignature']:
1.133 + new_doc = self._embed_signature(signature, node.doc)
1.134 + node.doc = EncodedString(new_doc) # XXX
1.135 + return node
2.1 --- a/Cython/Compiler/Main.py Thu Sep 18 11:45:16 2008 +0200
2.2 +++ b/Cython/Compiler/Main.py Fri Sep 19 16:28:36 2008 +0200
2.3 @@ -80,6 +80,7 @@
2.4 from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
2.5 from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
2.6 from ParseTreeTransforms import ResolveOptions
2.7 + from AutoDocTransforms import EmbedSignature
2.8 from Optimize import FlattenInListTransform, SwitchTransform, OptimizeRefcounting
2.9 from Buffer import IntroduceBufferAuxiliaryVars
2.10 from ModuleNode import check_c_classes
2.11 @@ -96,6 +97,7 @@
2.12 PostParse(self),
2.13 _specific_post_parse,
2.14 ResolveOptions(self, self.pragma_overrides),
2.15 + EmbedSignature(self),
2.16 FlattenInListTransform(),
2.17 WithTransform(self),
2.18 DecoratorTransform(self),
3.1 --- a/Cython/Compiler/Options.py Thu Sep 18 11:45:16 2008 +0200
3.2 +++ b/Cython/Compiler/Options.py Fri Sep 19 16:28:36 2008 +0200
3.3 @@ -56,11 +56,13 @@
3.4
3.5 # Declare pragmas
3.6 option_types = {
3.7 - 'boundscheck' : bool
3.8 + 'boundscheck' : bool,
3.9 + 'embedsignature' : bool,
3.10 }
3.11
3.12 option_defaults = {
3.13 - 'boundscheck' : True
3.14 + 'boundscheck' : True,
3.15 + 'embedsignature' : False,
3.16 }
3.17
3.18 def parse_option_value(name, value):
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/Tools/cython-epydoc.py Fri Sep 19 16:28:36 2008 +0200
4.3 @@ -0,0 +1,45 @@
4.4 +#! /usr/bin/env python
4.5 +
4.6 +# --------------------------------------------------------------------
4.7 +
4.8 +import re
4.9 +from epydoc import docstringparser as dsp
4.10 +
4.11 +CYTHON_SIGNATURE_RE = re.compile(
4.12 + # Class name (for builtin methods)
4.13 + r'^\s*((?P<class>\w+)\.)?' +
4.14 + # The function name
4.15 + r'(?P<func>\w+)' +
4.16 + # The parameters
4.17 + r'\(((?P<self>(?:self|cls|mcs)),?)?(?P<params>.*)\)' +
4.18 + # The return value (optional)
4.19 + r'(\s*(->)\s*(?P<return>\w+(?:\s*\w+)))?' +
4.20 + # The end marker
4.21 + r'\s*(?:\n|$)')
4.22 +
4.23 +parse_signature = dsp.parse_function_signature
4.24 +
4.25 +def parse_function_signature(func_doc, doc_source,
4.26 + docformat, parse_errors):
4.27 + PYTHON_SIGNATURE_RE = dsp._SIGNATURE_RE
4.28 + assert PYTHON_SIGNATURE_RE is not CYTHON_SIGNATURE_RE
4.29 + try:
4.30 + dsp._SIGNATURE_RE = CYTHON_SIGNATURE_RE
4.31 + found = parse_signature(func_doc, doc_source,
4.32 + docformat, parse_errors)
4.33 + dsp._SIGNATURE_RE = PYTHON_SIGNATURE_RE
4.34 + if not found:
4.35 + found = parse_signature(func_doc, doc_source,
4.36 + docformat, parse_errors)
4.37 + return found
4.38 + finally:
4.39 + dsp._SIGNATURE_RE = PYTHON_SIGNATURE_RE
4.40 +
4.41 +dsp.parse_function_signature = parse_function_signature
4.42 +
4.43 +# --------------------------------------------------------------------
4.44 +
4.45 +from epydoc.cli import cli
4.46 +cli()
4.47 +
4.48 +# --------------------------------------------------------------------
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/tests/run/embedsignatures.pyx Fri Sep 19 16:28:36 2008 +0200
5.3 @@ -0,0 +1,107 @@
5.4 +#cython: embedsignature=True
5.5 +
5.6 +# note the r, we use \n below
5.7 +__doc__ = ur"""
5.8 + >>> print (Ext.a.__doc__)
5.9 + Ext.a(self)
5.10 +
5.11 + >>> print (Ext.b.__doc__)
5.12 + Ext.b(self, a, b, c)
5.13 +
5.14 + >>> print (Ext.c.__doc__)
5.15 + Ext.c(self, a, b, c=1)
5.16 +
5.17 + >>> print (Ext.d.__doc__)
5.18 + Ext.d(self, a, b, *, c=88)
5.19 +
5.20 + >>> print (Ext.e.__doc__)
5.21 + Ext.e(self, a, b, c=88, **kwds)
5.22 +
5.23 + >>> print (Ext.f.__doc__)
5.24 + Ext.f(self, a, b, *, c, d=42)
5.25 +
5.26 + >>> print (Ext.g.__doc__)
5.27 + Ext.g(self, a, b, *, c, d=42, e=17, f, **kwds)
5.28 +
5.29 + >>> print (Ext.h.__doc__)
5.30 + Ext.h(self, a, b, *args, c, d=42, e=17, f, **kwds)
5.31 +
5.32 + >>> print (Ext.k.__doc__)
5.33 + Ext.k(self, a, b, c=1, *args, d=42, e=17, f, **kwds)
5.34 +
5.35 + >>> print (Ext.get_int.__doc__)
5.36 + Ext.get_int(self) -> int
5.37 +
5.38 + >>> print (Ext.get_float.__doc__)
5.39 + Ext.get_float(self) -> float
5.40 +
5.41 + >>> print (Ext.clone.__doc__)
5.42 + Ext.clone(self) -> Ext
5.43 +
5.44 + >>> print (foo.__doc__)
5.45 + foo()
5.46 +
5.47 + >>> with_doc_1.__doc__
5.48 + 'with_doc_1(a, b, c)\nExisting string'
5.49 +
5.50 + >>> with_doc_2.__doc__
5.51 + 'with_doc_2(a, b, c)\n\n Existing string\n '
5.52 +
5.53 + >>> types.__doc__
5.54 + 'types(Ext a, int b, int c, float d, e)'
5.55 +
5.56 +"""
5.57 +
5.58 +cdef class Ext:
5.59 +
5.60 + def a(self):
5.61 + pass
5.62 +
5.63 + def b(self, a, b, c):
5.64 + pass
5.65 +
5.66 + def c(self, a, b, c=1):
5.67 + pass
5.68 +
5.69 + def d(self, a, b, *, c = 88):
5.70 + pass
5.71 +
5.72 + def e(self, a, b, c = 88, **kwds):
5.73 + pass
5.74 +
5.75 + def f(self, a, b, *, c, d = 42):
5.76 + pass
5.77 +
5.78 + def g(self, a, b, *, c, d = 42, e = 17, f, **kwds):
5.79 + pass
5.80 +
5.81 + def h(self, a, b, *args, c, d = 42, e = 17, f, **kwds):
5.82 + pass
5.83 +
5.84 + def k(self, a, b, c=1, *args, d = 42, e = 17, f, **kwds):
5.85 + pass
5.86 +
5.87 + cpdef int get_int(self):
5.88 + return 0
5.89 +
5.90 + cpdef float get_float(self):
5.91 + return 0.0
5.92 +
5.93 + cpdef Ext clone(self):
5.94 + return Ext()
5.95 +
5.96 +def foo():
5.97 + pass
5.98 +
5.99 +def types(Ext a, int b, unsigned short c, float d, e):
5.100 + pass
5.101 +
5.102 +def with_doc_1(a, b, c):
5.103 + """Existing string"""
5.104 + pass
5.105 +
5.106 +def with_doc_2(a, b, c):
5.107 + """
5.108 + Existing string
5.109 + """
5.110 + pass
