@@ -387,28 +387,33 @@ def ispackage(path):
387
387
388
388
def source_synopsis (file ):
389
389
"""Return the one-line summary of a file object, if present"""
390
+
390
391
if hasattr (file , 'buffer' ):
391
392
file = file .buffer
392
393
if isinstance (file , io .TextIOBase ):
393
394
try :
394
- file = io .BytesIO (bytes (file .read (), 'utf-8' ))
395
+ source = file .read ()
396
+ if isinstance (source , bytes ):
397
+ source = source .decode ('utf-8' )
395
398
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 ()
399
+ source = file .read ().decode ('latin-1' )
400
+ else :
401
+ # Binary file
402
+ try :
403
+ source = tokenize .untokenize (tokenize .tokenize (file .readline ))
404
+ except (SyntaxError , tokenize .TokenError , UnicodeDecodeError , ValueError ):
405
+ return None
410
406
411
- return None
407
+ try :
408
+ tree = ast .parse (source )
409
+ if (tree .body and isinstance (tree .body [0 ], ast .Expr ) and
410
+ isinstance (tree .body [0 ].value , ast .Constant ) and
411
+ isinstance (tree .body [0 ].value .vlaue , str )):
412
+ docstring = tree .body [0 ].value .s
413
+ return docstring .strip ().split ('\n ' )[0 ].strip ()
414
+ return None
415
+ except (SyntaxError , ValueError ) as e :
416
+ return None
412
417
413
418
def synopsis (filename , cache = {}):
414
419
"""Get the one-line summary out of a module file."""
0 commit comments