ai-content-maker/.venv/Lib/site-packages/Cython/Compiler/AutoDocTransforms.py

319 lines
12 KiB
Python
Raw Permalink Normal View History

2024-05-03 04:18:51 +03:00
from __future__ import absolute_import, print_function
from .Visitor import CythonTransform
from .StringEncoding import EncodedString
from . import Options
from . import PyrexTypes
from ..CodeWriter import ExpressionWriter
from .Errors import warning
class AnnotationWriter(ExpressionWriter):
"""
A Cython code writer for Python expressions in argument/variable annotations.
"""
def __init__(self, description=None):
"""description is optional. If specified it is used in
warning messages for the nodes that don't convert to string properly.
If not specified then no messages are generated.
"""
ExpressionWriter.__init__(self)
self.description = description
self.incomplete = False
def visit_Node(self, node):
self.put(u"<???>")
self.incomplete = True
if self.description:
warning(node.pos,
"Failed to convert code to string representation in {0}".format(
self.description), level=1)
def visit_LambdaNode(self, node):
# XXX Should we do better?
self.put("<lambda>")
self.incomplete = True
if self.description:
warning(node.pos,
"Failed to convert lambda to string representation in {0}".format(
self.description), level=1)
def visit_UnicodeNode(self, node):
# Discard Unicode prefix in annotations. Any tool looking at them
# would probably expect Py3 string semantics.
self.emit_string(node, "")
def visit_AnnotationNode(self, node):
self.put(node.string.unicode_value)
class EmbedSignature(CythonTransform):
def __init__(self, context):
super(EmbedSignature, self).__init__(context)
self.class_name = None
self.class_node = None
def _fmt_expr(self, node):
writer = ExpressionWriter()
result = writer.write(node)
# print(type(node).__name__, '-->', result)
return result
def _fmt_annotation(self, node):
writer = AnnotationWriter()
result = writer.write(node)
# print(type(node).__name__, '-->', result)
return result
def _setup_format(self):
signature_format = self.current_directives['embedsignature.format']
self.is_format_c = signature_format == 'c'
self.is_format_python = signature_format == 'python'
self.is_format_clinic = signature_format == 'clinic'
def _fmt_arg(self, arg):
arg_doc = arg.name
annotation = None
defaultval = None
if arg.is_self_arg:
if self.is_format_clinic:
arg_doc = '$self'
elif arg.is_type_arg:
if self.is_format_clinic:
arg_doc = '$type'
elif self.is_format_c:
if arg.type is not PyrexTypes.py_object_type:
arg_doc = arg.type.declaration_code(arg.name, for_display=1)
elif self.is_format_python:
if not arg.annotation:
annotation = self._fmt_type(arg.type)
if arg.annotation:
if not self.is_format_clinic:
annotation = self._fmt_annotation(arg.annotation)
if arg.default:
defaultval = self._fmt_expr(arg.default)
if annotation:
arg_doc = arg_doc + (': %s' % annotation)
if defaultval:
arg_doc = arg_doc + (' = %s' % defaultval)
elif defaultval:
arg_doc = arg_doc + ('=%s' % defaultval)
return arg_doc
def _fmt_star_arg(self, arg):
arg_doc = arg.name
if arg.annotation:
if not self.is_format_clinic:
annotation = self._fmt_annotation(arg.annotation)
arg_doc = arg_doc + (': %s' % annotation)
return arg_doc
def _fmt_arglist(self, args,
npoargs=0, npargs=0, pargs=None,
nkargs=0, kargs=None,
hide_self=False):
arglist = []
for arg in args:
if not hide_self or not arg.entry.is_self_arg:
arg_doc = self._fmt_arg(arg)
arglist.append(arg_doc)
if pargs:
arg_doc = self._fmt_star_arg(pargs)
arglist.insert(npargs + npoargs, '*%s' % arg_doc)
elif nkargs:
arglist.insert(npargs + npoargs, '*')
if npoargs:
arglist.insert(npoargs, '/')
if kargs:
arg_doc = self._fmt_star_arg(kargs)
arglist.append('**%s' % arg_doc)
return arglist
def _fmt_type(self, type):
if type is PyrexTypes.py_object_type:
return None
elif self.is_format_c:
code = type.declaration_code("", for_display=1)
return code
elif self.is_format_python:
annotation = None
if type.is_string:
annotation = self.current_directives['c_string_type']
elif type.is_numeric:
annotation = type.py_type_name()
if annotation is None:
code = type.declaration_code('', for_display=1)
annotation = code.replace(' ', '_').replace('*', 'p')
return annotation
return None
def _fmt_signature(self, cls_name, func_name, args,
npoargs=0, npargs=0, pargs=None,
nkargs=0, kargs=None,
return_expr=None, return_type=None,
hide_self=False):
arglist = self._fmt_arglist(
args, npoargs, npargs, pargs, nkargs, kargs,
hide_self=hide_self,
)
arglist_doc = ', '.join(arglist)
func_doc = '%s(%s)' % (func_name, arglist_doc)
if self.is_format_c and cls_name:
func_doc = '%s.%s' % (cls_name, func_doc)
if not self.is_format_clinic:
ret_doc = None
if return_expr:
ret_doc = self._fmt_annotation(return_expr)
elif return_type:
ret_doc = self._fmt_type(return_type)
if ret_doc:
func_doc = '%s -> %s' % (func_doc, ret_doc)
return func_doc
def _embed_signature(self, signature, node_doc):
if self.is_format_clinic and self.current_directives['binding']:
return node_doc
if node_doc:
if self.is_format_clinic:
docfmt = "%s\n--\n\n%s"
else:
docfmt = "%s\n%s"
return docfmt % (signature, node_doc)
else:
if self.is_format_clinic:
docfmt = "%s\n--\n\n"
else:
docfmt = "%s"
return docfmt % signature
def __call__(self, node):
if not Options.docstrings:
return node
else:
return super(EmbedSignature, self).__call__(node)
def visit_ClassDefNode(self, node):
oldname = self.class_name
oldclass = self.class_node
self.class_node = node
try:
# PyClassDefNode
self.class_name = node.name
except AttributeError:
# CClassDefNode
self.class_name = node.class_name
self.visitchildren(node)
self.class_name = oldname
self.class_node = oldclass
return node
def visit_LambdaNode(self, node):
# lambda expressions so not have signature or inner functions
return node
def visit_DefNode(self, node):
if not self.current_directives['embedsignature']:
return node
self._setup_format()
is_constructor = False
hide_self = False
if node.entry.is_special:
is_constructor = self.class_node and node.name == '__init__'
if not is_constructor:
return node
class_name = None
func_name = node.name
if self.is_format_c:
func_name = self.class_name
hide_self = True
else:
class_name, func_name = self.class_name, node.name
npoargs = getattr(node, 'num_posonly_args', 0)
nkargs = getattr(node, 'num_kwonly_args', 0)
npargs = len(node.args) - nkargs - npoargs
signature = self._fmt_signature(
class_name, func_name, node.args,
npoargs, npargs, node.star_arg,
nkargs, node.starstar_arg,
return_expr=node.return_type_annotation,
return_type=None, hide_self=hide_self)
if signature:
if is_constructor and self.is_format_c:
doc_holder = self.class_node.entry.type.scope
else:
doc_holder = node.entry
if doc_holder.doc is not None:
old_doc = doc_holder.doc
elif not is_constructor and getattr(node, 'py_func', None) is not None:
old_doc = node.py_func.entry.doc
else:
old_doc = None
new_doc = self._embed_signature(signature, old_doc)
doc_holder.doc = EncodedString(new_doc)
if not is_constructor and getattr(node, 'py_func', None) is not None:
node.py_func.entry.doc = EncodedString(new_doc)
return node
def visit_CFuncDefNode(self, node):
if not node.overridable: # not cpdef FOO(...):
return node
if not self.current_directives['embedsignature']:
return node
self._setup_format()
signature = self._fmt_signature(
self.class_name, node.declarator.base.name,
node.declarator.args,
return_type=node.return_type)
if signature:
if node.entry.doc is not None:
old_doc = node.entry.doc
elif getattr(node, 'py_func', None) is not None:
old_doc = node.py_func.entry.doc
else:
old_doc = None
new_doc = self._embed_signature(signature, old_doc)
node.entry.doc = EncodedString(new_doc)
py_func = getattr(node, 'py_func', None)
if py_func is not None:
py_func.entry.doc = EncodedString(new_doc)
return node
def visit_PropertyNode(self, node):
if not self.current_directives['embedsignature']:
return node
self._setup_format()
entry = node.entry
body = node.body
prop_name = entry.name
type_name = None
if entry.visibility == 'public':
if self.is_format_c:
# property synthesised from a cdef public attribute
type_name = entry.type.declaration_code("", for_display=1)
if not entry.type.is_pyobject:
type_name = "'%s'" % type_name
elif entry.type.is_extension_type:
type_name = entry.type.module_name + '.' + type_name
elif self.is_format_python:
type_name = self._fmt_type(entry.type)
if type_name is None:
for stat in body.stats:
if stat.name != '__get__':
continue
if self.is_format_c:
prop_name = '%s.%s' % (self.class_name, prop_name)
ret_annotation = stat.return_type_annotation
if ret_annotation:
type_name = self._fmt_annotation(ret_annotation)
if type_name is not None :
signature = '%s: %s' % (prop_name, type_name)
new_doc = self._embed_signature(signature, entry.doc)
if not self.is_format_clinic:
entry.doc = EncodedString(new_doc)
return node