Skip to content

Commit 82c1c78

Browse files
committed
- Issue #16514: Fix regression causing a traceback when sys.path[0] is None
(actually, any non-string or non-bytes type).
1 parent 23089ab commit 82c1c78

File tree

6 files changed

+111
-77
lines changed

6 files changed

+111
-77
lines changed

Doc/library/sys.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,9 @@ always available.
783783
current directory first. Notice that the script directory is inserted *before*
784784
the entries inserted as a result of :envvar:`PYTHONPATH`.
785785

786-
A program is free to modify this list for its own purposes.
786+
A program is free to modify this list for its own purposes. Only strings
787+
and bytes should be added to :data:`sys.path`; all other data types are
788+
ignored during import.
787789

788790

789791
.. seealso::

Doc/reference/import.rst

+15-9
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,10 @@ environment variable and various other installation- and
540540
implementation-specific defaults. Entries in :data:`sys.path` can name
541541
directories on the file system, zip files, and potentially other "locations"
542542
(see the :mod:`site` module) that should be searched for modules, such as
543-
URLs, or database queries.
543+
URLs, or database queries. Only strings and bytes should be present on
544+
:data:`sys.path`; all other data types are ignored. The encoding of bytes
545+
entries is determined by the individual :term:`path entry finders <path entry
546+
finder>`.
544547

545548
The :term:`path based finder` is a :term:`meta path finder`, so the import
546549
machinery begins the :term:`import path` search by calling the path
@@ -563,14 +566,17 @@ free to remove cache entries from :data:`sys.path_importer_cache` forcing
563566
the path based finder to perform the path entry search again [#fnpic]_.
564567

565568
If the path entry is not present in the cache, the path based finder iterates
566-
over every callable in :data:`sys.path_hooks`. Each of the
567-
:term:`path entry hooks <path entry hook>` in this list is called with a
568-
single argument, the path entry to be searched. This callable may either
569-
return a :term:`path entry finder` that can handle the path entry, or it may
570-
raise :exc:`ImportError`.
571-
An :exc:`ImportError` is used by the path based finder to signal that the hook
572-
cannot find a :term:`path entry finder` for that :term:`path entry`. The
573-
exception is ignored and :term:`import path` iteration continues.
569+
over every callable in :data:`sys.path_hooks`. Each of the :term:`path entry
570+
hooks <path entry hook>` in this list is called with a single argument, the
571+
path entry to be searched. This callable may either return a :term:`path
572+
entry finder` that can handle the path entry, or it may raise
573+
:exc:`ImportError`. An :exc:`ImportError` is used by the path based finder to
574+
signal that the hook cannot find a :term:`path entry finder` for that
575+
:term:`path entry`. The exception is ignored and :term:`import path`
576+
iteration continues. The hook should expect either a string or bytes object;
577+
the encoding of bytes objects is up to the hook (e.g. it may be a file system
578+
encoding, UTF-8, or something else), and if the hook cannot decode the
579+
argument, it should raise :exc:`ImportError`.
574580

575581
If :data:`sys.path_hooks` iteration ends with no :term:`path entry finder`
576582
being returned, then the path based finder's :meth:`find_module()` method

Lib/importlib/_bootstrap.py

+2
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,8 @@ def _get_loader(cls, fullname, path):
12811281
# the list of paths that will become its __path__
12821282
namespace_path = []
12831283
for entry in path:
1284+
if not isinstance(entry, (str, bytes)):
1285+
continue
12841286
finder = cls._path_importer_cache(entry)
12851287
if finder is not None:
12861288
if hasattr(finder, 'find_loader'):

Lib/test/test_importlib/import_/test_path.py

+21-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
from importlib import _bootstrap
22
from importlib import machinery
3+
from importlib import import_module
34
from .. import util
45
from . import util as import_util
5-
import imp
66
import os
77
import sys
8-
import tempfile
9-
from test import support
10-
from types import MethodType
8+
from types import ModuleType
119
import unittest
1210
import warnings
11+
import zipimport
1312

1413

1514
class FinderTests(unittest.TestCase):
@@ -89,6 +88,24 @@ def test_path_importer_cache_empty_string(self):
8988
self.assertIs(loader, importer)
9089
self.assertIn(os.curdir, sys.path_importer_cache)
9190

91+
def test_None_on_sys_path(self):
92+
# Putting None in sys.path[0] caused an import regression from Python
93+
# 3.2: http://bugs.python.org/issue16514
94+
new_path = sys.path[:]
95+
new_path.insert(0, None)
96+
new_path_importer_cache = sys.path_importer_cache.copy()
97+
new_path_importer_cache.pop(None, None)
98+
new_path_hooks = [zipimport.zipimporter,
99+
_bootstrap.FileFinder.path_hook(
100+
*_bootstrap._get_supported_file_loaders())]
101+
with util.uncache('email'):
102+
with util.import_state(meta_path=sys.meta_path[:],
103+
path=new_path,
104+
path_importer_cache=new_path_importer_cache,
105+
path_hooks=new_path_hooks):
106+
module = import_module('email')
107+
self.assertIsInstance(module, ModuleType)
108+
92109

93110
def test_main():
94111
from test.support import run_unittest

Misc/NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 3.3.1?
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #16514: Fix regression causing a traceback when sys.path[0] is None
16+
(actually, any non-string or non-bytes type).
17+
1518
- Issue #16306: Fix multiple error messages when unknown command line
1619
parameters where passed to the interpreter. Patch by Hieu Nguyen.
1720

0 commit comments

Comments
 (0)