diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2018-04-15 11:52:57 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-15 11:52:57 (GMT) |
commit | 82a948105920100ca2ec5c2340bc3890adcfe778 (patch) | |
tree | b6ed9b9402c0e83386082933015b706e58db40d7 /Lib/pydoc.py | |
parent | 480ab05d5fee2b8fa161f799af33086a4e68c7dd (diff) | |
download | cpython-82a948105920100ca2ec5c2340bc3890adcfe778.zip cpython-82a948105920100ca2ec5c2340bc3890adcfe778.tar.gz cpython-82a948105920100ca2ec5c2340bc3890adcfe778.tar.bz2 |
bpo-33185: Fix regression in pydoc CLI sys.path handling (GH-6419)
The pydoc CLI assumed -m pydoc would add the empty string
to sys.path, and hence got confused when it switched to
adding the full initial working directory instead.
This refactors the pydoc CLI path manipulation to be
more testable, and ensures it won't accidentally
remove the standard library directory containing
pydoc itself from sys.path.
Diffstat (limited to 'Lib/pydoc.py')
-rw-r--r-- | Lib/pydoc.py | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 7d0b1d8..735ad9d 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2614,18 +2614,50 @@ def browse(port=0, *, open_browser=True, hostname='localhost'): def ispath(x): return isinstance(x, str) and x.find(os.sep) >= 0 +def _get_revised_path(given_path, argv0): + """Ensures current directory is on returned path, and argv0 directory is not + + Exception: argv0 dir is left alone if it's also pydoc's directory. + + Returns a new path entry list, or None if no adjustment is needed. + """ + # Scripts may get the current directory in their path by default if they're + # run with the -m switch, or directly from the current directory. + # The interactive prompt also allows imports from the current directory. + + # Accordingly, if the current directory is already present, don't make + # any changes to the given_path + if '' in given_path or os.curdir in given_path or os.getcwd() in given_path: + return None + + # Otherwise, add the current directory to the given path, and remove the + # script directory (as long as the latter isn't also pydoc's directory. + stdlib_dir = os.path.dirname(__file__) + script_dir = os.path.dirname(argv0) + revised_path = given_path.copy() + if script_dir in given_path and not os.path.samefile(script_dir, stdlib_dir): + revised_path.remove(script_dir) + revised_path.insert(0, os.getcwd()) + return revised_path + + +# Note: the tests only cover _get_revised_path, not _adjust_cli_path itself +def _adjust_cli_sys_path(): + """Ensures current directory is on sys.path, and __main__ directory is not + + Exception: __main__ dir is left alone if it's also pydoc's directory. + """ + revised_path = _get_revised_path(sys.path, sys.argv[0]) + if revised_path is not None: + sys.path[:] = revised_path + + def cli(): """Command-line interface (looks at sys.argv to decide what to do).""" import getopt class BadUsage(Exception): pass - # Scripts don't get the current directory in their path by default - # unless they are run with the '-m' switch - if '' not in sys.path: - scriptdir = os.path.dirname(sys.argv[0]) - if scriptdir in sys.path: - sys.path.remove(scriptdir) - sys.path.insert(0, '.') + _adjust_cli_sys_path() try: opts, args = getopt.getopt(sys.argv[1:], 'bk:n:p:w') |