diff -r f40f015258fc Lib/inspect.py --- a/Lib/inspect.py Sun Sep 15 15:40:18 2013 -0500 +++ b/Lib/inspect.py Mon Sep 16 19:57:07 2013 +0300 @@ -2109,3 +2109,49 @@ rendered += ' -> {}'.format(anno) return rendered + +def _main(): + """ Logic for inspecting an object given at command line """ + import argparse + import importlib + + parser = argparse.ArgumentParser() + parser.add_argument( + 'object', + help="The object to be analysed. " + "It supports the 'module:qualname' syntax") + parser.add_argument( + '-s', '--source', action='store_true', + help='Dump the source of the object') + + args = parser.parse_args() + + mod = args.object + if mod.find(":") > -1: + module, attrs = mod.split(":", 1) + loaded_module = importlib.import_module(module) + parts = attrs.split(".") + obj = loaded_module + for part in parts: + obj = getattr(obj, part) + else: + obj = loaded_module = importlib.import_module(mod) + + if loaded_module.__name__ in sys.builtin_module_names: + print("Can't get info for builtin modules.", file=sys.stderr) + exit(1) + + print('\nHEADERS\n-------\n') + print('Origin: {}'.format(getsourcefile(loaded_module))) + print('Cached: {}'.format(loaded_module.__cached__)) + print('Loader: {}'.format(repr(loaded_module.__loader__))) + if loaded_module.__package__: + package = importlib.import_module(loaded_module.__package__) + print('Submodule search path: {}'.format(package.__path__)) + print('\n') + + if args.source: + print(getsource(obj)) + +if __name__ == "__main__": + _main() diff -r f40f015258fc Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Sun Sep 15 15:40:18 2013 -0500 +++ b/Lib/test/test_inspect.py Mon Sep 16 19:57:07 2013 +0300 @@ -9,10 +9,11 @@ import os import shutil import functools +import importlib from os.path import normcase from test.support import run_unittest, TESTFN, DirsOnSysPath - +from test.script_helper import assert_python_ok, assert_python_failure from test import inspect_fodder as mod from test import inspect_fodder2 as mod2 @@ -2372,6 +2373,36 @@ __wrapped__ = func self.assertIsNone(inspect.unwrap(C())) +class TestMain(unittest.TestCase): + def test_only_source(self): + module = importlib.import_module('unittest') + rc, out, err = assert_python_ok('-m', 'inspect', + 'unittest', '--source') + lines = out.decode().splitlines() + # ignore the info section and the final newline + self.assertEqual(lines[10:-1], inspect.getsource(module).splitlines()) + self.assertEqual(err, b'') + + def test_qualname_source(self): + module = importlib.import_module('concurrent.futures') + member = getattr(module, 'ThreadPoolExecutor') + rc, out, err = assert_python_ok('-m', 'inspect', + 'concurrent.futures:ThreadPoolExecutor', + '--source') + lines = out.decode().splitlines() + # ignore the info section and the final newline + self.assertEqual(lines[10:-1], + inspect.getsource(member).splitlines()) + self.assertEqual(err, b'') + + def test_builtins(self): + module = importlib.import_module('unittest') + _, out, err = assert_python_failure('-m', 'inspect', + 'sys', '--source') + lines = err.decode().splitlines() + self.assertEqual(lines, ["Can't get info for builtin modules."]) + + def test_main(): run_unittest( @@ -2380,7 +2411,7 @@ TestGetcallargsFunctions, TestGetcallargsMethods, TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject, - TestBoundArguments, TestGetClosureVars, TestUnwrap + TestBoundArguments, TestGetClosureVars, TestUnwrap, TestMain ) if __name__ == "__main__":