1212import numpydoc .docscrape as npds
1313
1414from ._analysis import KnownImport , TypesDatabase
15- from ._utils import ContextFormatter , DocstubError , accumulate_qualname , escape_qualname
15+ from ._utils import DocstubError , ErrorReporter , accumulate_qualname , escape_qualname
1616
1717logger = logging .getLogger (__name__ )
1818
@@ -80,7 +80,7 @@ def many_as_tuple(cls, types):
8080
8181 @classmethod
8282 def as_generator (cls , * , yield_types , receive_types = (), return_types = ()):
83- """Create new ``Generator`` type from yield, receive and return types.
83+ """Create copy_with ``Generator`` type from yield, receive and return types.
8484
8585 Parameters
8686 ----------
@@ -257,7 +257,7 @@ def __init__(self, *, types_db=None, replace_doctypes=None, **kwargs):
257257
258258 super ().__init__ (** kwargs )
259259
260- self .stats = {"grammar_errors " : 0 }
260+ self .stats = {"syntax_errors " : 0 }
261261
262262 def doctype_to_annotation (self , doctype ):
263263 """Turn a type description in a docstring into a type annotation.
@@ -289,7 +289,7 @@ def doctype_to_annotation(self, doctype):
289289 lark .exceptions .ParseError ,
290290 QualnameIsKeyword ,
291291 ):
292- self .stats ["grammar_errors " ] += 1
292+ self .stats ["syntax_errors " ] += 1
293293 raise
294294 finally :
295295 self ._collected_imports = None
@@ -443,7 +443,7 @@ class DocstringAnnotations:
443443 ----------
444444 docstring : str
445445 transformer : DoctypeTransformer
446- ctx : ~.ContextFormatter
446+ reporter : ~.ErrorReporter
447447
448448 Examples
449449 --------
@@ -457,32 +457,32 @@ class DocstringAnnotations:
457457 >>> transformer = DoctypeTransformer()
458458 >>> annotations = DocstringAnnotations(docstring, transformer=transformer)
459459 >>> annotations.parameters.keys()
460- invalid syntax in doctype
460+ Invalid syntax in docstring type annotation
461461 some invalid syntax
462462 ^
463463 <BLANKLINE>
464- unknown name in doctype: 'unknown.symbol'
464+ Unknown name in doctype: 'unknown.symbol'
465465 unknown.symbol
466466 ^^^^^^^^^^^^^^
467467 <BLANKLINE>
468468 dict_keys(['a', 'b', 'c'])
469469 """
470470
471- def __init__ (self , docstring , * , transformer , ctx = None ):
471+ def __init__ (self , docstring , * , transformer , reporter = None ):
472472 """
473473 Parameters
474474 ----------
475475 docstring : str
476476 transformer : DoctypeTransformer
477- ctx : ~.ContextFormatter , optional
477+ reporter : ~.ErrorReporter , optional
478478 """
479479 self .docstring = docstring
480480 self .np_docstring = npds .NumpyDocString (docstring )
481481 self .transformer = transformer
482482
483- if ctx is None :
484- ctx = ContextFormatter (line = 0 )
485- self .ctx : ContextFormatter = ctx
483+ if reporter is None :
484+ reporter = ErrorReporter (line = 0 )
485+ self .reporter : ErrorReporter = reporter
486486
487487 def _doctype_to_annotation (self , doctype , ds_line = 0 ):
488488 """Convert a type description to a Python-ready type.
@@ -501,7 +501,7 @@ def _doctype_to_annotation(self, doctype, ds_line=0):
501501 The transformed type, ready to be inserted into a stub file, with
502502 necessary imports attached.
503503 """
504- ctx = self .ctx . with_line ( offset = ds_line )
504+ reporter = self .reporter . copy_with ( line_offset = ds_line )
505505
506506 try :
507507 annotation , unknown_qualnames = self .transformer .doctype_to_annotation (
@@ -513,21 +513,23 @@ def _doctype_to_annotation(self, doctype, ds_line=0):
513513 if hasattr (error , "get_context" ):
514514 details = error .get_context (doctype )
515515 details = details .replace ("^" , click .style ("^" , fg = "red" , bold = True ))
516- ctx .print_message ("invalid syntax in doctype" , details = details )
516+ reporter .message (
517+ "Invalid syntax in docstring type annotation" , details = details
518+ )
517519 return FallbackAnnotation
518520
519521 except lark .visitors .VisitError as e :
520522 tb = "\n " .join (traceback .format_exception (e .orig_exc ))
521523 details = f"doctype: { doctype !r} \n \n { tb } "
522- ctx . print_message ("unexpected error while parsing doctype" , details = details )
524+ reporter . message ("unexpected error while parsing doctype" , details = details )
523525 return FallbackAnnotation
524526
525527 else :
526528 for name , start_col , stop_col in unknown_qualnames :
527529 width = stop_col - start_col
528530 error_underline = click .style ("^" * width , fg = "red" , bold = True )
529531 details = f"{ doctype } \n { ' ' * start_col } { error_underline } \n "
530- ctx . print_message (f"unknown name in doctype: { name !r} " , details = details )
532+ reporter . message (f"Unknown name in doctype: { name !r} " , details = details )
531533 return annotation
532534
533535 @cached_property
@@ -553,7 +555,10 @@ def attributes(self):
553555 break
554556
555557 if attribute .name in annotations :
556- logger .warning ("duplicate parameter name %r, ignoring" , attribute .name )
558+ self .reporter .message (
559+ "duplicate attribute name in docstring" ,
560+ details = self .reporter .underline (attribute .name ),
561+ )
557562 continue
558563
559564 annotation = self ._doctype_to_annotation (attribute .type , ds_line = ds_line )
@@ -576,7 +581,10 @@ def parameters(self):
576581
577582 duplicates = param_section .keys () & other_section .keys ()
578583 for duplicate in duplicates :
579- logger .warning ("duplicate parameter name %r, ignoring" , duplicate )
584+ self .reporter .message (
585+ "duplicate attribute name in docstring" ,
586+ details = self .reporter .underline (duplicate ),
587+ )
580588
581589 # Last takes priority
582590 paramaters = other_section | param_section
@@ -653,20 +661,21 @@ def _handle_missing_whitespace(self, param):
653661 param : numpydoc.docscrape.Parameter
654662 """
655663 if ":" in param .name and param .type == "" :
656- msg = (
657- "Possibly missing whitespace between parameter and colon in "
658- "docstring, make sure to include it so that the type is parsed "
659- "properly!"
664+ msg = "Possibly missing whitespace between parameter and colon in docstring"
665+ underline = "" .join ("^" if c == ":" else " " for c in param .name )
666+ underline = click .style (underline , fg = "red" , bold = True )
667+ hint = (
668+ f"{ param .name } \n { underline } "
669+ f"\n Include whitespace so that the type is parsed properly!"
660670 )
661- hint = f"{ param .name } "
662671
663672 ds_line = 0
664673 for i , line in enumerate (self .docstring .split ("\n " )):
665674 if param .name in line :
666675 ds_line = i
667676 break
668- ctx = self .ctx . with_line ( offset = ds_line )
669- ctx . print_message (msg , details = hint )
677+ reporter = self .reporter . copy_with ( line_offset = ds_line )
678+ reporter . message (msg , details = hint )
670679
671680 new_name , new_type = param .name .split (":" , maxsplit = 1 )
672681 param = npds .Parameter (name = new_name , type = new_type , desc = param .desc )
@@ -693,7 +702,10 @@ def _section_annotations(self, name):
693702
694703 if param .name in annotated_params :
695704 # TODO make error
696- logger .warning ("duplicate parameter name %r, ignoring" , param .name )
705+ self .reporter .message (
706+ "duplicate parameter / attribute name in docstring" ,
707+ details = self .reporter .underline (param .name ),
708+ )
697709 continue
698710
699711 if param .type :
0 commit comments