@@ -76,7 +76,6 @@ class or function within a module or module in a package. If the
76
76
from collections import deque
77
77
from reprlib import Repr
78
78
from traceback import format_exception_only
79
- from token import tok_name
80
79
81
80
from _pyrepl .pager import (get_pager , pipe_pager ,
82
81
plain_pager , tempfile_pager , tty_pager )
@@ -387,28 +386,33 @@ def ispackage(path):
387
386
388
387
def source_synopsis (file ):
389
388
"""Return the one-line summary of a file object, if present"""
389
+
390
390
if hasattr (file , 'buffer' ):
391
391
file = file .buffer
392
392
if isinstance (file , io .TextIOBase ):
393
393
try :
394
- file = io .BytesIO (bytes (file .read (), 'utf-8' ))
394
+ source = file .read ()
395
+ if isinstance (source , bytes ):
396
+ source = source .decode ('utf-8' )
395
397
except UnicodeEncodeError :
396
- # an exception will be raised if both utf-8 and latin-1 don't work
397
- file = io .BytesIO (bytes (file .read (), 'latin-1' ))
398
-
399
- tokens = tokenize .tokenize (file .readline )
400
-
401
- # tokenize always returns at least ENCODING and ENDMARKER
402
- for token in tokens :
403
- token_name = tok_name [token .type ]
404
- if token .name not in {'COMMENT' , 'NL' , 'ENCODING' }:
405
- break
406
-
407
- # xxx may not be set
408
- if token_name == 'STRING' :
409
- return ast .literal_eval (token .string ).strip ().split ('\n ' )[0 ].strip ()
398
+ source = file .read ().decode ('latin-1' )
399
+ else :
400
+ # Binary file
401
+ try :
402
+ source = tokenize .untokenize (tokenize .tokenize (file .readline ))
403
+ except (SyntaxError , tokenize .TokenError , UnicodeDecodeError , ValueError ):
404
+ return None
410
405
411
- return None
406
+ try :
407
+ tree = ast .parse (source )
408
+ if (tree .body and isinstance (tree .body [0 ], ast .Expr ) and
409
+ isinstance (tree .body [0 ].value , ast .Constant ) and
410
+ isinstance (tree .body [0 ].value .vlaue , str )):
411
+ docstring = tree .body [0 ].value .value
412
+ return docstring .strip ().split ('\n ' )[0 ].strip ()
413
+ return None
414
+ except (SyntaxError , ValueError ) as e :
415
+ return None
412
416
413
417
def synopsis (filename , cache = {}):
414
418
"""Get the one-line summary out of a module file."""
0 commit comments