cpython: 2e1335245f8f (original) (raw)
Mercurial > cpython
changeset 85780:2e1335245f8f
Close #18626: add a basic CLI for the inspect module [#18626]
Nick Coghlan ncoghlan@gmail.com | |
---|---|
date | Sun, 22 Sep 2013 22:46:49 +1000 |
parents | 0c17a461f34c |
children | 8620aea9bbca |
files | Doc/library/inspect.rst Doc/whatsnew/3.4.rst Lib/inspect.py Lib/test/test_inspect.py Misc/NEWS |
diffstat | 5 files changed, 130 insertions(+), 3 deletions(-)[+] [-] Doc/library/inspect.rst 17 Doc/whatsnew/3.4.rst 6 Lib/inspect.py 61 Lib/test/test_inspect.py 46 Misc/NEWS 3 |
line wrap: on
line diff
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -1006,3 +1006,20 @@ updated as expected:
return an empty dictionary.
.. versionadded:: 3.3
+
+
+Command Line Interface
+----------------------
+
+The :mod:inspect
module also provides a basic introspection capability
+from the command line.
+
+.. program:: inspect
+
+By default, accepts the name of a module and prints the source of that
+module. A class or function within the module can be printed instead by
+appended a colon and the qualified name of the target object.
+
+.. cmdoption:: --details
+
--- a/Doc/whatsnew/3.4.rst
+++ b/Doc/whatsnew/3.4.rst
@@ -264,11 +264,15 @@ New :func:functools.singledispatch
dec
inspect
-------
+
+The inspect module now offers a basic command line interface to quickly
+display source code and other information for modules, classes and
+functions.
+
:func:~inspect.unwrap
makes it easy to unravel wrapper function chains
created by :func:functools.wraps
(and any other API that sets the
__wrapped__
attribute on a wrapper function).
-
mmap
----
--- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2109,3 +2109,64 @@ class Signature: rendered += ' -> {}'.format(anno) return rendered + +def _main():
- parser = argparse.ArgumentParser()
- parser.add_argument(
'object',[](#l3.15)
help="The object to be analysed. "[](#l3.16)
"It supports the 'module:qualname' syntax")[](#l3.17)
- parser.add_argument(
'-d', '--details', action='store_true',[](#l3.19)
help='Display info about the module rather than its source code')[](#l3.20)
- target = args.object
- mod_name, has_attrs, attrs = target.partition(":")
- try:
obj = module = importlib.import_module(mod_name)[](#l3.27)
- except Exception as exc:
msg = "Failed to import {} ({}: {})".format(mod_name,[](#l3.29)
type(exc).__name__,[](#l3.30)
exc)[](#l3.31)
print(msg, file=sys.stderr)[](#l3.32)
exit(2)[](#l3.33)
- if has_attrs:
parts = attrs.split(".")[](#l3.36)
obj = module[](#l3.37)
for part in parts:[](#l3.38)
obj = getattr(obj, part)[](#l3.39)
- if module.name in sys.builtin_module_names:
print("Can't get info for builtin modules.", file=sys.stderr)[](#l3.42)
exit(1)[](#l3.43)
- if args.details:
print('Target: {}'.format(target))[](#l3.46)
print('Origin: {}'.format(getsourcefile(module)))[](#l3.47)
print('Cached: {}'.format(module.__cached__))[](#l3.48)
if obj is module:[](#l3.49)
print('Loader: {}'.format(repr(module.__loader__)))[](#l3.50)
if hasattr(module, '__path__'):[](#l3.51)
print('Submodule search path: {}'.format(module.__path__))[](#l3.52)
else:[](#l3.53)
try:[](#l3.54)
__, lineno = findsource(obj)[](#l3.55)
except Exception:[](#l3.56)
pass[](#l3.57)
else:[](#l3.58)
print('Line: {}'.format(lineno))[](#l3.59)
--- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -9,10 +9,11 @@ import collections 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,47 @@ class TestUnwrap(unittest.TestCase): wrapped = func self.assertIsNone(inspect.unwrap(C())) +class TestMain(unittest.TestCase):
- def test_only_source(self):
module = importlib.import_module('unittest')[](#l4.22)
rc, out, err = assert_python_ok('-m', 'inspect',[](#l4.23)
'unittest')[](#l4.24)
lines = out.decode().splitlines()[](#l4.25)
# ignore the final newline[](#l4.26)
self.assertEqual(lines[:-1], inspect.getsource(module).splitlines())[](#l4.27)
self.assertEqual(err, b'')[](#l4.28)
- def test_qualname_source(self):
module = importlib.import_module('concurrent.futures')[](#l4.31)
member = getattr(module, 'ThreadPoolExecutor')[](#l4.32)
rc, out, err = assert_python_ok('-m', 'inspect',[](#l4.33)
'concurrent.futures:ThreadPoolExecutor')[](#l4.34)
lines = out.decode().splitlines()[](#l4.35)
# ignore the final newline[](#l4.36)
self.assertEqual(lines[:-1],[](#l4.37)
inspect.getsource(member).splitlines())[](#l4.38)
self.assertEqual(err, b'')[](#l4.39)
- def test_builtins(self):
module = importlib.import_module('unittest')[](#l4.42)
_, out, err = assert_python_failure('-m', 'inspect',[](#l4.43)
'sys')[](#l4.44)
lines = err.decode().splitlines()[](#l4.45)
self.assertEqual(lines, ["Can't get info for builtin modules."])[](#l4.46)
- def test_details(self):
module = importlib.import_module('unittest')[](#l4.49)
rc, out, err = assert_python_ok('-m', 'inspect',[](#l4.50)
'unittest', '--details')[](#l4.51)
output = out.decode()[](#l4.52)
# Just a quick sanity check on the output[](#l4.53)
self.assertIn(module.__name__, output)[](#l4.54)
self.assertIn(module.__file__, output)[](#l4.55)
self.assertIn(module.__cached__, output)[](#l4.56)
self.assertEqual(err, b'')[](#l4.57)
+ + + def test_main(): run_unittest( @@ -2380,7 +2422,7 @@ def test_main(): TestGetcallargsFunctions, TestGetcallargsMethods, TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject,
TestBoundArguments, TestGetClosureVars, TestUnwrap[](#l4.68)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins Library ------- +- Issue #18626: the inspect module now offers a basic command line