Get the one-line summary out of a module file.
(filename, cache={})
| 363 | return result |
| 364 | |
| 365 | def synopsis(filename, cache={}): |
| 366 | """Get the one-line summary out of a module file.""" |
| 367 | mtime = os.stat(filename).st_mtime |
| 368 | lastupdate, result = cache.get(filename, (None, None)) |
| 369 | if lastupdate is None or lastupdate < mtime: |
| 370 | # Look for binary suffixes first, falling back to source. |
| 371 | if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)): |
| 372 | loader_cls = importlib.machinery.SourcelessFileLoader |
| 373 | elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)): |
| 374 | loader_cls = importlib.machinery.ExtensionFileLoader |
| 375 | else: |
| 376 | loader_cls = None |
| 377 | # Now handle the choice. |
| 378 | if loader_cls is None: |
| 379 | # Must be a source file. |
| 380 | try: |
| 381 | file = tokenize.open(filename) |
| 382 | except OSError: |
| 383 | # module can't be opened, so skip it |
| 384 | return None |
| 385 | # text modules can be directly examined |
| 386 | with file: |
| 387 | result = source_synopsis(file) |
| 388 | else: |
| 389 | # Must be a binary module, which has to be imported. |
| 390 | loader = loader_cls('__temp__', filename) |
| 391 | # XXX We probably don't need to pass in the loader here. |
| 392 | spec = importlib.util.spec_from_file_location('__temp__', filename, |
| 393 | loader=loader) |
| 394 | try: |
| 395 | module = importlib._bootstrap._load(spec) |
| 396 | except: |
| 397 | return None |
| 398 | del sys.modules['__temp__'] |
| 399 | result = module.__doc__.splitlines()[0] if module.__doc__ else None |
| 400 | # Cache the result. |
| 401 | cache[filename] = (mtime, result) |
| 402 | return result |
| 403 | |
| 404 | class ErrorDuringImport(Exception): |
| 405 | """Errors that occurred while trying to import something to document it.""" |
nothing calls this directly
no test coverage detected