11"""Transform types defined in docstrings to Python parsable types."""
22
33import logging
4+ import textwrap
45from dataclasses import dataclass , field
56from pathlib import Path
67
8+ import click
79import lark
810import lark .visitors
911from numpydoc .docscrape import NumpyDocString
@@ -33,7 +35,7 @@ def _find_one_token(tree: lark.Tree, *, name: str) -> lark.Token:
3335 return tokens [0 ]
3436
3537
36- @dataclass (frozen = True , slots = True )
38+ @dataclass (frozen = True , slots = True , kw_only = True )
3739class Annotation :
3840 """Python-ready type annotation with attached import information."""
3941
@@ -148,6 +150,30 @@ def __init__(self, *, inspector, replace_doctypes, **kwargs):
148150 self ._collected_imports = None
149151 super ().__init__ (** kwargs )
150152
153+ def transform (self , doctype ):
154+ """Turn a type description in a docstring into a type annotation.
155+
156+ Parameters
157+ ----------
158+ doctype : str
159+ The doctype to parse.
160+
161+ Returns
162+ -------
163+ annotation : Annotation
164+ The parsed annotation.
165+ """
166+ try :
167+ self ._collected_imports = set ()
168+ tree = _lark .parse (doctype )
169+ value = super ().transform (tree = tree )
170+ annotation = Annotation (
171+ value = value , imports = frozenset (self ._collected_imports )
172+ )
173+ return annotation
174+ finally :
175+ self ._collected_imports = None
176+
151177 def __default__ (self , data , children , meta ):
152178 """Unpack children of rule nodes by default.
153179
@@ -172,30 +198,6 @@ def __default__(self, data, children, meta):
172198 out = children
173199 return out
174200
175- def transform (self , tree ):
176- """
177-
178- Parameters
179- ----------
180- tree : lark.Tree
181- The
182-
183- Returns
184- -------
185- annotation : Annotation
186- The doctype formatted as a stub-file compatible string with
187- necessary imports attached.
188- """
189- try :
190- self ._collected_imports = set ()
191- value = super ().transform (tree = tree )
192- annotation = Annotation (
193- value = value , imports = frozenset (self ._collected_imports )
194- )
195- return annotation
196- finally :
197- self ._collected_imports = None
198-
199201 def annotation (self , tree ):
200202 out = " | " .join (tree .children )
201203 return out
@@ -293,10 +295,20 @@ def _find_import(self, qualname):
293295
294296
295297class DocstringAnnotations :
296- def __init__ (self , docstring , * , transformer ):
298+ def __init__ (self , docstring , * , transformer , source = None ):
297299 self .docstring = docstring
298300 self .np_docstring = NumpyDocString (docstring )
299301 self .transformer = transformer
302+ self .source = source
303+
304+ def _format_grammar_error (self , error , doctype ):
305+ msg = "doctype doesn't conform to grammar"
306+ details = doctype
307+ if hasattr (error , "get_context" ):
308+ details = error .get_context (doctype )
309+ details = textwrap .indent (details , prefix = " " )
310+ out = f"{ click .style (self .source , bold = True )} { msg } \n { details } "
311+ return out
300312
301313 def _doctype_to_annotation (self , doctype ):
302314 """Convert a type description to a Python-ready type.
@@ -316,14 +328,19 @@ def _doctype_to_annotation(self, doctype):
316328 necessary imports attached.
317329 """
318330 try :
319- tree = _lark .parse (doctype )
320- annotation = self .transformer .transform (tree )
331+ annotation = self .transformer .transform (doctype )
321332 return annotation
322- except lark .visitors .VisitError as e :
323- logger .exception ("couldn't parse doctype: %r" , doctype , exc_info = e .orig_exc )
333+ except (lark .exceptions .LexError , lark .exceptions .ParseError ) as error :
334+ msg = self ._format_grammar_error (error = error , doctype = doctype )
335+ click .echo (msg )
324336 return ErrorFallbackAnnotation
325- except Exception :
326- logger .exception ("couldn't parse doctype: %r" , doctype )
337+ except lark .visitors .VisitError as e :
338+ logger .exception (
339+ "unexpected error parsing doctype %r in %s, falling back to Any" ,
340+ doctype ,
341+ self .source ,
342+ exc_info = e .orig_exc ,
343+ )
327344 return ErrorFallbackAnnotation
328345
329346 @property
0 commit comments