22
33# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/04_docments.ipynb.
44
5- # %% ../nbs/04_docments.ipynb 2
6- from __future__ import annotations
5+ # %% auto 0
6+ __all__ = ['empty' , 'docstring' , 'parse_docstring' , 'isdataclass' , 'get_dataclass_source' , 'get_source' , 'get_name' , 'qual_name' ,
7+ 'docments' , 'sig_source' , 'extract_docstrings' , 'DocmentTbl' , 'DocmentList' , 'DocmentText' , 'sig2str' ,
8+ 'ShowDocRenderer' , 'MarkdownRenderer' ]
79
10+ # %% ../nbs/04_docments.ipynb
811import re ,ast ,inspect
912from tokenize import tokenize ,COMMENT
1013from ast import parse ,FunctionDef ,AsyncFunctionDef ,AnnAssign
1720from .meta import delegates
1821from . import docscrape
1922from textwrap import fill
20- from inspect import isclass ,getdoc
21-
22- # %% auto 0
23- __all__ = ['empty' , 'docstring' , 'parse_docstring' , 'isdataclass' , 'get_dataclass_source' , 'get_source' , 'get_name' , 'qual_name' ,
24- 'docments' , 'sig2str' , 'sig_source' , 'extract_docstrings' , 'DocmentTbl' , 'DocmentList' , 'DocmentsText' ,
25- 'ShowDocRenderer' , 'MarkdownRenderer' ]
23+ from inspect import isclass ,getdoc ,signature
2624
2725# %% ../nbs/04_docments.ipynb
2826def docstring (sym ):
@@ -112,7 +110,8 @@ def _get_full(p, docs):
112110# %% ../nbs/04_docments.ipynb
113111def _merge_doc (dm , npdoc ):
114112 if not npdoc : return dm
115- if not dm .anno or dm .anno == empty : dm .anno = npdoc .type
113+ if not isinstance (dm , dict ): return dm or '\n ' .join (npdoc .desc )
114+ # if not dm.anno or dm.anno==empty: dm.anno = npdoc.type
116115 if not dm .docment : dm .docment = '\n ' .join (npdoc .desc )
117116 return dm
118117
@@ -146,64 +145,25 @@ def qual_name(obj):
146145 return get_name (obj )
147146
148147# %% ../nbs/04_docments.ipynb
149- def _docments (s , returns = True , eval_str = False , args_kwargs = False ):
150- "`dict` of parameter names to 'docment-style' comments in function or string `s`"
148+ def docments (s , full = False , eval_str = False , returns = True , args_kwargs = False ):
149+ "Get docments for `s`"
150+ if isclass (s ) and not is_dataclass (s ): s = s .__init__
151+ try : sig = signature_ex (s , eval_str = eval_str )
152+ except ValueError : return AttrDict ()
151153 nps = parse_docstring (s )
152- if isclass (s ) and not is_dataclass (s ): s = s .__init__ # Constructor for a class
153- comments = {o .start [0 ]:_clean_comment (o .string ) for o in _tokens (s ) if o .type == COMMENT }
154- parms = _param_locs (s , returns = returns , args_kwargs = args_kwargs ) or {}
155- docs = {arg :_get_comment (line , arg , comments , parms ) for line ,arg in parms .items ()}
156-
157- sig = signature_ex (s , True )
158- res = {name :_get_full (p , docs ) for name ,p in sig .parameters .items ()}
159- if returns : res ['return' ] = AttrDict (docment = docs .get ('return' ), anno = sig .return_annotation , default = empty )
160- res = _merge_docs (res , nps )
161- if eval_str :
162- hints = type_hints (s )
163- for k ,v in res .items ():
164- if k in hints : v ['anno' ] = hints .get (k )
165- return res
166-
167- # %% ../nbs/04_docments.ipynb
168- @delegates (_docments )
169- def docments (elt , full = False , args_kwargs = False , ** kwargs ):
170- "Generates a `docment`"
171- if full : args_kwargs = True
172- r = {}
173- params = set (signature (elt ).parameters )
174- params .add ('return' )
175-
176- def _update_docments (f , r ):
177- if hasattr (f , '__delwrap__' ): _update_docments (f .__delwrap__ , r )
178- r .update ({k :v for k ,v in _docments (f , ** kwargs ).items () if k in params
179- and (v .get ('docment' , None ) or not nested_idx (r , k , 'docment' ))})
180-
181- _update_docments (elt , r )
182- if not full : r = {k :v ['docment' ] for k ,v in r .items ()}
183- return AttrDict (r )
184-
185- # %% ../nbs/04_docments.ipynb
186- def sig2str (func ):
187- "Generate function signature with docments as comments"
188- docs = docments (func , full = True )
189- params = []
190- for k ,v in docs .items ():
191- if k == 'return' : continue
192- anno = getattr (v ['anno' ], '__name__' , str (v ['anno' ])) if v ['anno' ] != inspect ._empty else ''
193- if '|' in str (v ['anno' ]): anno = str (v ['anno' ])
194- p = k + (f':{ anno } ' if anno and anno != 'inspect._empty' else '' )
195- if v ['default' ] != inspect ._empty :
196- d = getattr (v ['default' ], '__name__' , v ['default' ]) if hasattr (v ['default' ], '__name__' ) else v ['default' ]
197- p += f'={ d } ' if d is not None else '=None'
198- if v ['docment' ]: p += f' # { v ["docment" ]} '
199- params .append (p )
154+ docs = {}
155+ while s :
156+ p = _param_locs (s , returns = returns , args_kwargs = args_kwargs ) or {}
157+ c = {o .start [0 ]:_clean_comment (o .string ) for o in _tokens (s ) if o .type == COMMENT }
158+ for k ,v in p .items ():
159+ if v not in docs : docs [v ] = _get_comment (k , v , c , p )
160+ s = getattr (s , '__delwrap__' , None )
200161
201- ret = docs .get ('return' , {})
202- ret_str = ':'
203- if ret and ret .get ('anno' )!= inspect ._empty :
204- ret_str = f"->{ getattr (ret ['anno' ], '__name__' , str (ret ['anno' ]))} " + (f': # { ret ["docment" ]} ' if ret .get ('docment' ) else ':' )
205- doc_str = f' "{ func .__doc__ } "' if func .__doc__ else ''
206- return f"def { func .__name__ } (\n " + ",\n " .join (params ) + f"\n ){ ret_str } \n { doc_str } "
162+ res = {k :_get_full (v , docs ) if full else docs .get (k ) for k ,v in sig .parameters .items ()}
163+ if returns :
164+ if full : res ['return' ] = AttrDict (docment = docs .get ('return' ), anno = sig .return_annotation , default = empty )
165+ else : res ['return' ] = docs .get ('return' )
166+ return AttrDict (_merge_docs (res , nps ))
207167
208168# %% ../nbs/04_docments.ipynb
209169def sig_source (obj ):
@@ -294,7 +254,7 @@ def __init__(self, obj, verbose=True, returns=True):
294254 super ().__init__ (obj )
295255 self .verbose = verbose
296256 self .returns = False if isdataclass (obj ) else returns
297- try : self .params = L (signature_ex (obj , eval_str = True ).parameters .keys ())
257+ try : self .params = L (signature (obj , eval_str = True ).parameters .keys ())
298258 except (ValueError ,TypeError ): self .params = []
299259 for d in self .dm .values (): d ['docment' ] = ifnone (d ['docment' ], inspect ._empty )
300260
@@ -354,7 +314,11 @@ def _repr_markdown_(self): return '\n'.join(self._fmt(k,v) for k,v in self.dm.it
354314 __repr__ = __str__ = _repr_markdown_
355315
356316# %% ../nbs/04_docments.ipynb
357- class DocmentsText (_DocmentBase ):
317+ class DocmentText (_DocmentBase ):
318+ def __init__ (self , obj , maxline = 160 , docstring = True ):
319+ super ().__init__ (obj )
320+ self .maxline ,self .docstring = maxline ,docstring
321+
358322 def _fmt_param (self , nm , p ):
359323 anno ,default = p .get ('anno' ,empty ), p .get ('default' ,empty )
360324 return nm + (f':{ _maybe_nm (anno )} ' if anno != empty else '' ) + (f'={ repr (default )} ' if default != empty else '' )
@@ -366,20 +330,31 @@ def _ret_str(self):
366330 doc = f" # { ret ['docment' ]} " if ret .get ('docment' ) else ''
367331 return f"){ anno } :{ doc } "
368332
333+ @property
334+ def params (self ): return [(self ._fmt_param (k ,v ), v .get ('docment' ,'' )) for k ,v in self .dm .items () if k != 'return' ]
335+
369336 def __str__ (self ):
370- params = [(self ._fmt_param (k ,v ), v .get ('docment' ,'' )) for k ,v in self .dm .items () if k != 'return' ]
371337 lines ,curr = [],[]
372- for fmt ,doc in params :
338+ for fmt ,doc in self .params :
339+ comment = f' # { doc } ' if doc else ''
340+ if curr and len (', ' .join (curr ))+ len (fmt )+ len (comment )> self .maxline :
341+ lines .append (', ' .join (curr ) + ',' )
342+ curr = []
373343 curr .append (fmt )
374- if doc : lines .append (( ', ' .join (curr ), doc ) ); curr = []
375- if curr : lines .append (( ', ' .join (curr ), '' ))
376- body = [ f" { line } { '' if i == len ( lines ) - 1 else ',' } { f' # { doc } ' if doc else '' } " for i ,( line , doc ) in enumerate ( lines )]
377- docstr = f' "{ self .obj .__doc__ } "' if self .obj .__doc__ else ''
378- return f"def { self .obj .__name__ } (\n " + " \n " . join ( body ) + f" \n { self ._ret_str } \n { docstr } "
344+ if doc : lines .append (', ' .join (curr ) + ',' + comment ); curr = []
345+ if curr : lines .append (', ' .join (curr ))
346+ body = ' \n ' . join ( lines )
347+ docstr = f' "{ self .obj .__doc__ } "' if self .docstring and self . obj .__doc__ else ''
348+ return f"def { self .obj .__name__ } (\n { body } \n { self ._ret_str } \n { docstr } "
379349
380350 __repr__ = __str__
381351 def _repr_markdown_ (self ): return f"```python\n { self } \n ```"
382352
353+ # %% ../nbs/04_docments.ipynb
354+ def sig2str (func , maxline = 160 ):
355+ "Generate function signature with docments as comments"
356+ return DocmentText (func , maxline = maxline , docstring = False )
357+
383358# %% ../nbs/04_docments.ipynb
384359def _docstring (sym ):
385360 npdoc = parse_docstring (sym )
@@ -391,17 +366,17 @@ def _fullname(o):
391366 return name if module is None or module in ('__main__' ,'builtins' ) else module + '.' + name
392367
393368class ShowDocRenderer :
394- def __init__ (self , sym , name :str | None = None , title_level :int = 3 ):
369+ def __init__ (self , sym , name :str | None = None , title_level :int = 3 , maxline : int = 120 ):
395370 "Show documentation for `sym`"
396371 sym = getattr (sym , '__wrapped__' , sym )
397372 sym = getattr (sym , 'fget' , None ) or getattr (sym , 'fset' , None ) or sym
398373 store_attr ()
399374 self .nm = name or qual_name (sym )
400375 self .isfunc = inspect .isfunction (sym )
401- try : self .sig = signature_ex (sym , eval_str = True )
376+ try : self .sig = signature (sym , eval_str = True )
402377 except (ValueError ,TypeError ): self .sig = None
403378 self .docs = _docstring (sym )
404- self .dm = DocmentList (sym )
379+ self .dm = DocmentText (sym , maxline = maxline , docstring = False )
405380 self .fn = _fullname (sym )
406381
407382 __repr__ = basic_repr ()
@@ -420,30 +395,15 @@ def _show_param(param):
420395 return res
421396
422397# %% ../nbs/04_docments.ipynb
423- def _fmt_sig (sig ):
424- if sig is None : return ''
425- p = {k :v for k ,v in sig .parameters .items ()}
426- _params = [_show_param (p [k ]) for k in p .keys () if k != 'self' ]
427- return "(" + ', ' .join (_params ) + ")"
428-
429- def _wrap_sig (s ):
430- "wrap a signature to appear on multiple lines if necessary."
431- pad = '> ' + ' ' * 5
432- indent = pad + ' ' * (s .find ('(' ) + 1 )
433- return fill (s , width = 80 , initial_indent = pad , subsequent_indent = indent )
434-
435398def _ital_first (s :str ):
436399 "Surround first line with * for markdown italics, preserving leading spaces"
437400 return re .sub (r'^(\s*)(.+)' , r'\1*\2*' , s , count = 1 )
438401
439402# %% ../nbs/04_docments.ipynb
440- def _ext_link (url , txt , xtra = "" ): return f'[{ txt } ]({ url } ){{target="_blank" { xtra } }}'
441-
442403class MarkdownRenderer (ShowDocRenderer ):
443404 "Markdown renderer for `show_doc`"
444405 def _repr_markdown_ (self ):
445- doc = _wrap_sig ( f" { self .nm } { _fmt_sig ( self . sig ) } " ) if self . sig else ' '
406+ doc = f'```python \n \n { self .dm } \n \n ``` '
446407 if self .docs : doc += f"\n \n { _ital_first (self .docs )} "
447- if self .dm .has_docment : doc += f"\n \n { self .dm } "
448408 return doc
449409 __repr__ = __str__ = _repr_markdown_
0 commit comments