155a74a43SLisandro Dalcin# ruff: noqa: UP008,UP031 255a74a43SLisandro Dalcinfrom Cython.Compiler import Options 355a74a43SLisandro Dalcinfrom Cython.Compiler import PyrexTypes 455a74a43SLisandro Dalcinfrom Cython.Compiler.ExprNodes import TupleNode 555a74a43SLisandro Dalcinfrom Cython.Compiler.Visitor import CythonTransform 655a74a43SLisandro Dalcinfrom Cython.Compiler.StringEncoding import EncodedString 755a74a43SLisandro Dalcinfrom Cython.Compiler.AutoDocTransforms import ( 855a74a43SLisandro Dalcin ExpressionWriter as BaseExpressionWriter, 955a74a43SLisandro Dalcin AnnotationWriter as BaseAnnotationWriter, 1055a74a43SLisandro Dalcin) 1155a74a43SLisandro Dalcin 1255a74a43SLisandro Dalcin 1355a74a43SLisandro Dalcinclass ExpressionWriter(BaseExpressionWriter): 1455a74a43SLisandro Dalcin 1555a74a43SLisandro Dalcin def visit_IndexNode(self, node): 1655a74a43SLisandro Dalcin self.visit(node.base) 1755a74a43SLisandro Dalcin self.put(u"[") 1855a74a43SLisandro Dalcin if isinstance(node.index, TupleNode): 1955a74a43SLisandro Dalcin if node.index.subexpr_nodes(): 2055a74a43SLisandro Dalcin self.emit_sequence(node.index) 2155a74a43SLisandro Dalcin else: 2255a74a43SLisandro Dalcin self.put(u"()") 2355a74a43SLisandro Dalcin else: 2455a74a43SLisandro Dalcin self.visit(node.index) 2555a74a43SLisandro Dalcin self.put(u"]") 2655a74a43SLisandro Dalcin 2755a74a43SLisandro Dalcin def visit_UnicodeNode(self, node): 2855a74a43SLisandro Dalcin self.emit_string(node, "") 2955a74a43SLisandro Dalcin 3055a74a43SLisandro Dalcin 3155a74a43SLisandro Dalcinclass AnnotationWriter(ExpressionWriter, BaseAnnotationWriter): 3255a74a43SLisandro Dalcin pass 3355a74a43SLisandro Dalcin 3455a74a43SLisandro Dalcin 3555a74a43SLisandro Dalcinclass EmbedSignature(CythonTransform): 3655a74a43SLisandro Dalcin 3755a74a43SLisandro Dalcin def __init__(self, context): 3855a74a43SLisandro Dalcin super(EmbedSignature, self).__init__(context) 3955a74a43SLisandro Dalcin self.class_name = None 4055a74a43SLisandro Dalcin self.class_node = None 4155a74a43SLisandro Dalcin 4255a74a43SLisandro Dalcin def _select_format(self, embed, clinic): 4355a74a43SLisandro Dalcin return embed 4455a74a43SLisandro Dalcin 4555a74a43SLisandro Dalcin def _fmt_expr(self, node): 4655a74a43SLisandro Dalcin writer = ExpressionWriter() 4755a74a43SLisandro Dalcin result = writer.write(node) 4855a74a43SLisandro Dalcin # print(type(node).__name__, '-->', result) 4955a74a43SLisandro Dalcin return result 5055a74a43SLisandro Dalcin 5155a74a43SLisandro Dalcin def _fmt_annotation(self, node): 5255a74a43SLisandro Dalcin writer = AnnotationWriter() 5355a74a43SLisandro Dalcin result = writer.write(node) 5455a74a43SLisandro Dalcin # print(type(node).__name__, '-->', result) 5555a74a43SLisandro Dalcin return result 5655a74a43SLisandro Dalcin 5755a74a43SLisandro Dalcin def _fmt_arg(self, arg): 5855a74a43SLisandro Dalcin annotation = None 5955a74a43SLisandro Dalcin if arg.is_self_arg: 6055a74a43SLisandro Dalcin doc = self._select_format(arg.name, '$self') 6155a74a43SLisandro Dalcin elif arg.is_type_arg: 6255a74a43SLisandro Dalcin doc = self._select_format(arg.name, '$type') 6355a74a43SLisandro Dalcin else: 6455a74a43SLisandro Dalcin doc = arg.name 6555a74a43SLisandro Dalcin if arg.type is PyrexTypes.py_object_type: 6655a74a43SLisandro Dalcin annotation = None 6755a74a43SLisandro Dalcin else: 6855a74a43SLisandro Dalcin annotation = arg.type.declaration_code('', for_display=1) 6955a74a43SLisandro Dalcin if arg.default and arg.default.is_none: 7055a74a43SLisandro Dalcin annotation += ' | None' 7155a74a43SLisandro Dalcin if arg.annotation: 7255a74a43SLisandro Dalcin annotation = self._fmt_annotation(arg.annotation) 7355a74a43SLisandro Dalcin annotation = self._select_format(annotation, None) 7455a74a43SLisandro Dalcin if annotation: 7555a74a43SLisandro Dalcin doc = doc + (': %s' % annotation) 7655a74a43SLisandro Dalcin if arg.default: 7755a74a43SLisandro Dalcin default = self._fmt_expr(arg.default) 7855a74a43SLisandro Dalcin doc = doc + (' = %s' % default) 7955a74a43SLisandro Dalcin elif arg.default: 8055a74a43SLisandro Dalcin default = self._fmt_expr(arg.default) 8155a74a43SLisandro Dalcin doc = doc + ('=%s' % default) 8255a74a43SLisandro Dalcin return doc 8355a74a43SLisandro Dalcin 8455a74a43SLisandro Dalcin def _fmt_star_arg(self, arg): 8555a74a43SLisandro Dalcin arg_doc = arg.name 8655a74a43SLisandro Dalcin if arg.annotation: 8755a74a43SLisandro Dalcin annotation = self._fmt_annotation(arg.annotation) 8855a74a43SLisandro Dalcin arg_doc = arg_doc + (': %s' % annotation) 8955a74a43SLisandro Dalcin return arg_doc 9055a74a43SLisandro Dalcin 9155a74a43SLisandro Dalcin def _fmt_arglist(self, args, 9255a74a43SLisandro Dalcin npoargs=0, npargs=0, pargs=None, 9355a74a43SLisandro Dalcin nkargs=0, kargs=None, 9455a74a43SLisandro Dalcin hide_self=False): 9555a74a43SLisandro Dalcin arglist = [] 9655a74a43SLisandro Dalcin for arg in args: 9755a74a43SLisandro Dalcin if not hide_self or not arg.entry.is_self_arg: 9855a74a43SLisandro Dalcin arg_doc = self._fmt_arg(arg) 9955a74a43SLisandro Dalcin arglist.append(arg_doc) 10055a74a43SLisandro Dalcin if pargs: 10155a74a43SLisandro Dalcin arg_doc = self._fmt_star_arg(pargs) 10255a74a43SLisandro Dalcin arglist.insert(npargs + npoargs, '*%s' % arg_doc) 10355a74a43SLisandro Dalcin elif nkargs: 10455a74a43SLisandro Dalcin arglist.insert(npargs + npoargs, '*') 10555a74a43SLisandro Dalcin if npoargs: 10655a74a43SLisandro Dalcin arglist.insert(npoargs, '/') 10755a74a43SLisandro Dalcin if kargs: 10855a74a43SLisandro Dalcin arg_doc = self._fmt_star_arg(kargs) 10955a74a43SLisandro Dalcin arglist.append('**%s' % arg_doc) 11055a74a43SLisandro Dalcin return arglist 11155a74a43SLisandro Dalcin 11255a74a43SLisandro Dalcin def _fmt_ret_type(self, ret): 11355a74a43SLisandro Dalcin if ret is PyrexTypes.py_object_type: 11455a74a43SLisandro Dalcin return None 11555a74a43SLisandro Dalcin else: 11655a74a43SLisandro Dalcin return ret.declaration_code("", for_display=1) 11755a74a43SLisandro Dalcin 11855a74a43SLisandro Dalcin def _fmt_signature(self, cls_name, func_name, args, 11955a74a43SLisandro Dalcin npoargs=0, npargs=0, pargs=None, 12055a74a43SLisandro Dalcin nkargs=0, kargs=None, 12155a74a43SLisandro Dalcin return_expr=None, 12255a74a43SLisandro Dalcin return_type=None, hide_self=False): 12355a74a43SLisandro Dalcin arglist = self._fmt_arglist(args, 12455a74a43SLisandro Dalcin npoargs, npargs, pargs, 12555a74a43SLisandro Dalcin nkargs, kargs, 12655a74a43SLisandro Dalcin hide_self=hide_self) 12755a74a43SLisandro Dalcin arglist_doc = ', '.join(arglist) 12855a74a43SLisandro Dalcin func_doc = '%s(%s)' % (func_name, arglist_doc) 12955a74a43SLisandro Dalcin if cls_name: 13055a74a43SLisandro Dalcin namespace = self._select_format('%s.' % cls_name, '') 13155a74a43SLisandro Dalcin func_doc = '%s%s' % (namespace, func_doc) 13255a74a43SLisandro Dalcin ret_doc = None 13355a74a43SLisandro Dalcin if return_expr: 13455a74a43SLisandro Dalcin ret_doc = self._fmt_annotation(return_expr) 13555a74a43SLisandro Dalcin elif return_type: 13655a74a43SLisandro Dalcin ret_doc = self._fmt_ret_type(return_type) 13755a74a43SLisandro Dalcin if ret_doc: 13855a74a43SLisandro Dalcin docfmt = self._select_format('%s -> %s', '%s -> (%s)') 13955a74a43SLisandro Dalcin func_doc = docfmt % (func_doc, ret_doc) 14055a74a43SLisandro Dalcin return func_doc 14155a74a43SLisandro Dalcin 142*b3f8c7a1SStefano Zampini def _fmt_relative_position(self, pos): 143*b3f8c7a1SStefano Zampini return ':'.join((str(pos[0].get_filenametable_entry()), str(pos[1]))) 144*b3f8c7a1SStefano Zampini 145*b3f8c7a1SStefano Zampini def _embed_signature(self, signature, pos, node_doc): 146*b3f8c7a1SStefano Zampini pos = self._fmt_relative_position(pos) 14755a74a43SLisandro Dalcin if node_doc: 148*b3f8c7a1SStefano Zampini docfmt = self._select_format("%s\n%s\n%s", "%s\n--\n\n%s") 149*b3f8c7a1SStefano Zampini return docfmt % (signature, node_doc, pos) 15055a74a43SLisandro Dalcin else: 151*b3f8c7a1SStefano Zampini docfmt = self._select_format("%s\n%s", "%s\n--\n\n%s") 152*b3f8c7a1SStefano Zampini return docfmt % (signature, pos) 15355a74a43SLisandro Dalcin 15455a74a43SLisandro Dalcin def __call__(self, node): 15555a74a43SLisandro Dalcin if not Options.docstrings: 15655a74a43SLisandro Dalcin return node 15755a74a43SLisandro Dalcin else: 15855a74a43SLisandro Dalcin return super(EmbedSignature, self).__call__(node) 15955a74a43SLisandro Dalcin 16055a74a43SLisandro Dalcin def visit_ClassDefNode(self, node): 16155a74a43SLisandro Dalcin oldname = self.class_name 16255a74a43SLisandro Dalcin oldclass = self.class_node 16355a74a43SLisandro Dalcin self.class_node = node 16455a74a43SLisandro Dalcin try: 16555a74a43SLisandro Dalcin # PyClassDefNode 16655a74a43SLisandro Dalcin self.class_name = node.name 16755a74a43SLisandro Dalcin except AttributeError: 16855a74a43SLisandro Dalcin # CClassDefNode 16955a74a43SLisandro Dalcin self.class_name = node.class_name 17055a74a43SLisandro Dalcin self.visitchildren(node) 17155a74a43SLisandro Dalcin self.class_name = oldname 17255a74a43SLisandro Dalcin self.class_node = oldclass 17355a74a43SLisandro Dalcin return node 17455a74a43SLisandro Dalcin 17555a74a43SLisandro Dalcin def visit_LambdaNode(self, node): 17655a74a43SLisandro Dalcin # lambda expressions so not have signature or inner functions 17755a74a43SLisandro Dalcin return node 17855a74a43SLisandro Dalcin 17955a74a43SLisandro Dalcin def visit_DefNode(self, node): 18055a74a43SLisandro Dalcin if not self.current_directives['embedsignature']: 18155a74a43SLisandro Dalcin return node 18255a74a43SLisandro Dalcin 18355a74a43SLisandro Dalcin is_constructor = False 18455a74a43SLisandro Dalcin hide_self = False 18555a74a43SLisandro Dalcin if node.entry.is_special: 18655a74a43SLisandro Dalcin is_constructor = self.class_node and node.name == '__init__' 18755a74a43SLisandro Dalcin if not is_constructor: 18855a74a43SLisandro Dalcin return node 18955a74a43SLisandro Dalcin class_name, func_name = None, self.class_name 19055a74a43SLisandro Dalcin hide_self = True 19155a74a43SLisandro Dalcin else: 19255a74a43SLisandro Dalcin class_name, func_name = self.class_name, node.name 19355a74a43SLisandro Dalcin 19455a74a43SLisandro Dalcin npoargs = getattr(node, 'num_posonly_args', 0) 19555a74a43SLisandro Dalcin nkargs = getattr(node, 'num_kwonly_args', 0) 19655a74a43SLisandro Dalcin npargs = len(node.args) - nkargs - npoargs 19755a74a43SLisandro Dalcin signature = self._fmt_signature( 19855a74a43SLisandro Dalcin class_name, func_name, node.args, 19955a74a43SLisandro Dalcin npoargs, npargs, node.star_arg, 20055a74a43SLisandro Dalcin nkargs, node.starstar_arg, 20155a74a43SLisandro Dalcin return_expr=node.return_type_annotation, 20255a74a43SLisandro Dalcin return_type=None, hide_self=hide_self) 20355a74a43SLisandro Dalcin if signature: 20455a74a43SLisandro Dalcin if is_constructor: 20555a74a43SLisandro Dalcin doc_holder = self.class_node.entry.type.scope 20655a74a43SLisandro Dalcin else: 20755a74a43SLisandro Dalcin doc_holder = node.entry 20855a74a43SLisandro Dalcin 20955a74a43SLisandro Dalcin if doc_holder.doc is not None: 21055a74a43SLisandro Dalcin old_doc = doc_holder.doc 21155a74a43SLisandro Dalcin elif not is_constructor and getattr(node, 'py_func', None) is not None: 21255a74a43SLisandro Dalcin old_doc = node.py_func.entry.doc 21355a74a43SLisandro Dalcin else: 21455a74a43SLisandro Dalcin old_doc = None 215*b3f8c7a1SStefano Zampini new_doc = self._embed_signature(signature, node.pos, old_doc) 21655a74a43SLisandro Dalcin doc_holder.doc = EncodedString(new_doc) 21755a74a43SLisandro Dalcin if not is_constructor and getattr(node, 'py_func', None) is not None: 21855a74a43SLisandro Dalcin node.py_func.entry.doc = EncodedString(new_doc) 21955a74a43SLisandro Dalcin return node 22055a74a43SLisandro Dalcin 22155a74a43SLisandro Dalcin def visit_CFuncDefNode(self, node): 22255a74a43SLisandro Dalcin if not self.current_directives['embedsignature']: 22355a74a43SLisandro Dalcin return node 22455a74a43SLisandro Dalcin if not node.overridable: # not cpdef FOO(...): 22555a74a43SLisandro Dalcin return node 22655a74a43SLisandro Dalcin 22755a74a43SLisandro Dalcin signature = self._fmt_signature( 22855a74a43SLisandro Dalcin self.class_name, node.declarator.base.name, 22955a74a43SLisandro Dalcin node.declarator.args, 23055a74a43SLisandro Dalcin return_type=node.return_type) 23155a74a43SLisandro Dalcin if signature: 23255a74a43SLisandro Dalcin if node.entry.doc is not None: 23355a74a43SLisandro Dalcin old_doc = node.entry.doc 23455a74a43SLisandro Dalcin elif getattr(node, 'py_func', None) is not None: 23555a74a43SLisandro Dalcin old_doc = node.py_func.entry.doc 23655a74a43SLisandro Dalcin else: 23755a74a43SLisandro Dalcin old_doc = None 238*b3f8c7a1SStefano Zampini new_doc = self._embed_signature(signature, node.pos, old_doc) 23955a74a43SLisandro Dalcin node.entry.doc = EncodedString(new_doc) 24055a74a43SLisandro Dalcin py_func = getattr(node, 'py_func', None) 24155a74a43SLisandro Dalcin if py_func is not None: 24255a74a43SLisandro Dalcin py_func.entry.doc = EncodedString(new_doc) 24355a74a43SLisandro Dalcin return node 24455a74a43SLisandro Dalcin 24555a74a43SLisandro Dalcin def visit_PropertyNode(self, node): 24655a74a43SLisandro Dalcin if not self.current_directives['embedsignature']: 24755a74a43SLisandro Dalcin return node 24855a74a43SLisandro Dalcin 24955a74a43SLisandro Dalcin entry = node.entry 25055a74a43SLisandro Dalcin body = node.body 25155a74a43SLisandro Dalcin prop_name = entry.name 25255a74a43SLisandro Dalcin type_name = None 25355a74a43SLisandro Dalcin if entry.visibility == 'public': 25455a74a43SLisandro Dalcin # property synthesised from a cdef public attribute 25555a74a43SLisandro Dalcin type_name = entry.type.declaration_code("", for_display=1) 25655a74a43SLisandro Dalcin if not entry.type.is_pyobject: 25755a74a43SLisandro Dalcin type_name = "'%s'" % type_name 25855a74a43SLisandro Dalcin elif entry.type.is_extension_type: 25955a74a43SLisandro Dalcin type_name = entry.type.module_name + '.' + type_name 26055a74a43SLisandro Dalcin if type_name is None: 26155a74a43SLisandro Dalcin for stat in body.stats: 26255a74a43SLisandro Dalcin if stat.name != '__get__': 26355a74a43SLisandro Dalcin continue 26455a74a43SLisandro Dalcin cls_name = self.class_name 26555a74a43SLisandro Dalcin if cls_name: 26655a74a43SLisandro Dalcin namespace = self._select_format('%s.' % cls_name, '') 26755a74a43SLisandro Dalcin prop_name = '%s%s' % (namespace, prop_name) 26855a74a43SLisandro Dalcin ret_annotation = stat.return_type_annotation 26955a74a43SLisandro Dalcin if ret_annotation: 27055a74a43SLisandro Dalcin type_name = self._fmt_annotation(ret_annotation) 27155a74a43SLisandro Dalcin if type_name is not None: 27255a74a43SLisandro Dalcin signature = '%s: %s' % (prop_name, type_name) 273*b3f8c7a1SStefano Zampini new_doc = self._embed_signature(signature, node.pos, entry.doc) 27455a74a43SLisandro Dalcin entry.doc = EncodedString(new_doc) 27555a74a43SLisandro Dalcin return node 27655a74a43SLisandro Dalcin 27755a74a43SLisandro Dalcin 27855a74a43SLisandro Dalcin# Monkeypatch AutoDocTransforms.EmbedSignature 27955a74a43SLisandro Dalcintry: 28055a74a43SLisandro Dalcin from Cython.Compiler import AutoDocTransforms 28155a74a43SLisandro Dalcin AutoDocTransforms.EmbedSignature = EmbedSignature 28255a74a43SLisandro Dalcinexcept Exception as exc: 28355a74a43SLisandro Dalcin import logging 28455a74a43SLisandro Dalcin logging.Logger(__name__).exception(exc) 28555a74a43SLisandro Dalcin 28655a74a43SLisandro Dalcin# Monkeypatch Nodes.raise_utility_code 28755a74a43SLisandro Dalcintry: 28855a74a43SLisandro Dalcin from Cython.Compiler.Nodes import raise_utility_code 28955a74a43SLisandro Dalcin code = raise_utility_code.impl 29055a74a43SLisandro Dalcin try: 29155a74a43SLisandro Dalcin ipos = code.index("if (tb) {\n#if CYTHON_COMPILING_IN_PYPY\n") 29255a74a43SLisandro Dalcin except ValueError: 29355a74a43SLisandro Dalcin ipos = None 29455a74a43SLisandro Dalcin else: 29555a74a43SLisandro Dalcin raise_utility_code.impl = code[:ipos] + code[ipos:].replace( 29655a74a43SLisandro Dalcin 'CYTHON_COMPILING_IN_PYPY', '!CYTHON_FAST_THREAD_STATE', 1) 29755a74a43SLisandro Dalcin del raise_utility_code, code, ipos 29855a74a43SLisandro Dalcinexcept Exception as exc: 29955a74a43SLisandro Dalcin import logging 30055a74a43SLisandro Dalcin logging.Logger(__name__).exception(exc) 301