Remove trailing whitespace.
[cython.git] / Cython / Compiler / AutoDocTransforms.py
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
7
8 class EmbedSignature(CythonTransform):
9
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
15
16     def _fmt_arg_defv(self, arg):
17         default_val = arg.default
18         if not default_val:
19             return None
20         try:
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':
32                     return repr_val[1:]
33             return repr_val
34         except Exception:
35             try:
36                 return default_val.name # XXX
37             except AttributeError:
38                 return '<???>'
39
40     def _fmt_arg(self, arg):
41         if arg.type is PyrexTypes.py_object_type or arg.is_self_arg:
42             doc = arg.name
43         else:
44             doc = arg.type.declaration_code(arg.name, for_display=1)
45         if arg.default:
46             arg_defv = self._fmt_arg_defv(arg)
47             if arg_defv:
48                 doc = doc + ('=%s' % arg_defv)
49         return doc
50
51     def _fmt_arglist(self, args,
52                      npargs=0, pargs=None,
53                      nkargs=0, kargs=None,
54                      hide_self=False):
55         arglist = []
56         for arg in 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)
60         if pargs:
61             arglist.insert(npargs, '*%s' % pargs.name)
62         elif nkargs:
63             arglist.insert(npargs, '*')
64         if kargs:
65             arglist.append('**%s' % kargs.name)
66         return arglist
67
68     def _fmt_ret_type(self, ret):
69         if ret is PyrexTypes.py_object_type:
70             return None
71         else:
72             return ret.declaration_code("", for_display=1)
73
74     def _fmt_signature(self, cls_name, func_name, args,
75                        npargs=0, pargs=None,
76                        nkargs=0, kargs=None,
77                        return_type=None, hide_self=False):
78         arglist = self._fmt_arglist(args,
79                                     npargs, pargs,
80                                     nkargs, kargs,
81                                     hide_self=hide_self)
82         arglist_doc = ', '.join(arglist)
83         func_doc = '%s(%s)' % (func_name, arglist_doc)
84         if cls_name:
85             func_doc = '%s.%s' % (cls_name, func_doc)
86         if return_type:
87             ret_doc = self._fmt_ret_type(return_type)
88             if ret_doc:
89                 func_doc = '%s -> %s' % (func_doc, ret_doc)
90         return func_doc
91
92     def _embed_signature(self, signature, node_doc):
93         if node_doc:
94             return "%s\n%s" % (signature, node_doc)
95         else:
96             return signature
97
98
99     def __call__(self, node):
100         if not Options.docstrings:
101             return node
102         else:
103             return super(EmbedSignature, self).__call__(node)
104
105     def visit_ClassDefNode(self, node):
106         oldname = self.class_name
107         oldclass = self.class_node
108         self.class_node = node
109         try:
110             # PyClassDefNode
111             self.class_name = node.name
112         except AttributeError:
113             # CClassDefNode
114             self.class_name = node.class_name
115         self.visitchildren(node)
116         self.class_name = oldname
117         self.class_node = oldclass
118         return node
119
120     def visit_DefNode(self, node):
121         if not self.current_directives['embedsignature']:
122             return node
123
124         is_constructor = False
125         hide_self = False
126         if node.entry.is_special:
127             is_constructor = self.class_node and node.name == '__init__'
128             if not is_constructor:
129                 return node
130             class_name, func_name = None, self.class_name
131             hide_self = True
132         else:
133             class_name, func_name = self.class_name, node.name
134
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)
142         if signature:
143             if is_constructor:
144                 doc_holder = self.class_node.entry.type.scope
145             else:
146                 doc_holder = node.entry
147
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
152             else:
153                 old_doc = None
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)
158         return node
159
160     def visit_CFuncDefNode(self, node):
161         if not self.current_directives['embedsignature']:
162             return node
163         if not node.overridable: # not cpdef FOO(...):
164             return node
165
166         signature = self._fmt_signature(
167             self.class_name, node.declarator.base.name,
168             node.declarator.args,
169             return_type=node.return_type)
170         if signature:
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
175             else:
176                 old_doc = None
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)
181         return node