1 from Cython.Compiler.Visitor import CythonTransform
2 from Cython.Compiler.Nodes import DefNode, CFuncDefNode
3 from Cython.Compiler.Errors import CompileError
4 from Cython.Compiler.StringEncoding import EncodedString
5 from Cython.Compiler import Options
6 from Cython.Compiler import PyrexTypes, ExprNodes
8 class EmbedSignature(CythonTransform):
10 def __init__(self, context):
11 super(EmbedSignature, self).__init__(context)
12 self.denv = None # XXX
13 self.class_name = None
14 self.class_node = None
16 def _fmt_arg_defv(self, arg):
17 default_val = arg.default
21 denv = self.denv # XXX
22 ctval = default_val.compile_time_value(self.denv)
23 repr_val = repr(ctval)
24 if isinstance(default_val, ExprNodes.UnicodeNode):
25 if repr_val[:1] != 'u':
26 return u'u%s' % repr_val
27 elif isinstance(default_val, ExprNodes.BytesNode):
28 if repr_val[:1] != 'b':
29 return u'b%s' % repr_val
30 elif isinstance(default_val, ExprNodes.StringNode):
31 if repr_val[:1] in 'ub':
36 return default_val.name # XXX
37 except AttributeError:
40 def _fmt_arg(self, arg):
41 if arg.type is PyrexTypes.py_object_type or arg.is_self_arg:
44 doc = arg.type.declaration_code(arg.name, for_display=1)
46 arg_defv = self._fmt_arg_defv(arg)
48 doc = doc + ('=%s' % arg_defv)
51 def _fmt_arglist(self, args,
57 if not hide_self or not arg.entry.is_self_arg:
58 arg_doc = self._fmt_arg(arg)
59 arglist.append(arg_doc)
61 arglist.insert(npargs, '*%s' % pargs.name)
63 arglist.insert(npargs, '*')
65 arglist.append('**%s' % kargs.name)
68 def _fmt_ret_type(self, ret):
69 if ret is PyrexTypes.py_object_type:
72 return ret.declaration_code("", for_display=1)
74 def _fmt_signature(self, cls_name, func_name, args,
77 return_type=None, hide_self=False):
78 arglist = self._fmt_arglist(args,
82 arglist_doc = ', '.join(arglist)
83 func_doc = '%s(%s)' % (func_name, arglist_doc)
85 func_doc = '%s.%s' % (cls_name, func_doc)
87 ret_doc = self._fmt_ret_type(return_type)
89 func_doc = '%s -> %s' % (func_doc, ret_doc)
92 def _embed_signature(self, signature, node_doc):
94 return "%s\n%s" % (signature, node_doc)
99 def __call__(self, node):
100 if not Options.docstrings:
103 return super(EmbedSignature, self).__call__(node)
105 def visit_ClassDefNode(self, node):
106 oldname = self.class_name
107 oldclass = self.class_node
108 self.class_node = node
111 self.class_name = node.name
112 except AttributeError:
114 self.class_name = node.class_name
115 self.visitchildren(node)
116 self.class_name = oldname
117 self.class_node = oldclass
120 def visit_DefNode(self, node):
121 if not self.current_directives['embedsignature']:
124 is_constructor = False
126 if node.entry.is_special:
127 is_constructor = self.class_node and node.name == '__init__'
128 if not is_constructor:
130 class_name, func_name = None, self.class_name
133 class_name, func_name = self.class_name, node.name
135 nkargs = getattr(node, 'num_kwonly_args', 0)
136 npargs = len(node.args) - nkargs
137 signature = self._fmt_signature(
138 class_name, func_name, node.args,
139 npargs, node.star_arg,
140 nkargs, node.starstar_arg,
141 return_type=None, hide_self=hide_self)
144 doc_holder = self.class_node.entry.type.scope
146 doc_holder = node.entry
148 if doc_holder.doc is not None:
149 old_doc = doc_holder.doc
150 elif not is_constructor and getattr(node, 'py_func', None) is not None:
151 old_doc = node.py_func.entry.doc
154 new_doc = self._embed_signature(signature, old_doc)
155 doc_holder.doc = EncodedString(new_doc)
156 if not is_constructor and getattr(node, 'py_func', None) is not None:
157 node.py_func.entry.doc = EncodedString(new_doc)
160 def visit_CFuncDefNode(self, node):
161 if not self.current_directives['embedsignature']:
163 if not node.overridable: # not cpdef FOO(...):
166 signature = self._fmt_signature(
167 self.class_name, node.declarator.base.name,
168 node.declarator.args,
169 return_type=node.return_type)
171 if node.entry.doc is not None:
172 old_doc = node.entry.doc
173 elif getattr(node, 'py_func', None) is not None:
174 old_doc = node.py_func.entry.doc
177 new_doc = self._embed_signature(signature, old_doc)
178 node.entry.doc = EncodedString(new_doc)
179 if hasattr(node, 'py_func') and node.py_func is not None:
180 node.py_func.entry.doc = EncodedString(new_doc)