Excuse me for following up my own post; also, for continuing to use Google Groups (but I've been browsing news.gmane.org, with the intention of using it in future - once I understand how to use it).
I should have read this: <http://legacy.python.org/dev/peps/pep-0451/> PEP 451 -- A ModuleSpec Type for the Import System Status: Final "*submodule_search_locations* The list of location strings, typically directory paths, in which to search for submodules. If the module is a package this will be set to a list (even an empty one). Otherwise it is None." That explains the thing that was most puzzling me. Here is the code I have written. If you want to try it, you'll need to: remove the 'self' argument; replace the methods self.prompt_print() and self.prompt_input() with the functions print() and input() respectively; replace the functions lines_in_file() and lines_of_code() with stubs, or some useful functions of your own devising. (Of course, I'll post my own code, if asked - but I don't want to make [more of?] a nuisance of myself by posting a lot of irrelevant crap unasked! My function lines_of_code() doesn't work properly, anyway - for example, the script 'antigravity.py', in the Python standard library, breaks it.) (No doubt Google Groups will reformat this horribly:) def process(self): """Not documented yet; but see documentation for the abstract base class UserToken, whose process() function this overrides. See also 'PEP 451 -- A ModuleSpec Type for the Import System'. """ while True: self.prompt_print('Type the name of a Python source code file') self.prompt_print('(omitting the invariable \'.py\' extension): ') name = self.prompt_input() if not name: return None # This is the only exit. else: spec = find_spec(name) if not spec: print('\'%s\' is not on the Python search path.' % name) elif not spec.has_location: print('\'%s\' is a Python built-in name.' % name) elif not hasattr(spec, 'submodule_search_locations'): print('BUG (?): No submodule_search_locations for \'%s.\'' % name) else: # spec exists, and has the required attribute (a list). submodules = spec.submodule_search_locations if submodules is not None: print('\'%s\' is a Python package (not built-in).' % name) if submodules: print('Submodule search location(s):') for s in submodules: print(s) else: print('No submodule search locations are listed.') elif not hasattr(spec, 'origin'): print('BUG (?): No origin string for %s.py.' % name) else: # attribute value is None, so this is not a package. path = spec.origin text = lines_in_file(path) code = lines_of_code(path) docs = text - code print('\n%s\nis a Python source file consisting of' % path) print('%u lines of plain text, of which' % text) print('%u are executable Python code, and' % code) print('%u are docstrings, comments, or blank lines.\n' % docs) -- https://mail.python.org/mailman/listinfo/python-list