Commit 035a1003 authored by Brett Cannon's avatar Brett Cannon

Issue #26667: Add path-like object support to importlib.util.

parent d5f92239
......@@ -1149,6 +1149,9 @@ an :term:`importer`.
The *optimization* parameter was added and the *debug_override* parameter
was deprecated.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
.. function:: source_from_cache(path)
......@@ -1162,6 +1165,9 @@ an :term:`importer`.
.. versionadded:: 3.4
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
.. function:: decode_source(source_bytes)
Decode the given bytes representing source code and return it as a string
......@@ -1298,6 +1304,9 @@ an :term:`importer`.
.. versionadded:: 3.4
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
.. class:: LazyLoader(loader)
A class which postpones the execution of the loader of a module until the
......
......@@ -68,8 +68,6 @@ New syntax features:
Standard library improvements:
* PEP 519: :ref:`Adding a file system path protocol <pep-519>`
Security improvements:
* On Linux, :func:`os.urandom` now blocks until the system urandom entropy pool
......@@ -513,6 +511,11 @@ restriction that :class:`importlib.machinery.BuiltinImporter` and
:class:`importlib.machinery.ExtensionFileLoader` couldn't be used with
:class:`importlib.util.LazyLoader`.
:func:`importlib.util.cache_from_source`,
:func:`importlib.util.source_from_cache`, and
:func:`importlib.util.spec_from_file_location` now accept a
:term:`path-like object`.
os
--
......@@ -528,6 +531,11 @@ The Linux ``getrandom()`` syscall (get random bytes) is now exposed as the new
:func:`os.getrandom` function.
(Contributed by Victor Stinner, part of the :pep:`524`)
See the summary for :ref:`PEP 519 <pep-519>` for details on how the
:mod:`os` and :mod:`os.path` modules now support
:term:`path-like objects <path-like object>`.
pickle
------
......
......@@ -279,6 +279,7 @@ def cache_from_source(path, debug_override=None, *, optimization=None):
message = 'debug_override or optimization must be set to None'
raise TypeError(message)
optimization = '' if debug_override else 1
path = _os.fspath(path)
head, tail = _path_split(path)
base, sep, rest = tail.rpartition('.')
tag = sys.implementation.cache_tag
......@@ -309,6 +310,7 @@ def source_from_cache(path):
"""
if sys.implementation.cache_tag is None:
raise NotImplementedError('sys.implementation.cache_tag is None')
path = _os.fspath(path)
head, pycache_filename = _path_split(path)
head, pycache = _path_split(head)
if pycache != _PYCACHE:
......@@ -536,6 +538,8 @@ def spec_from_file_location(name, location=None, *, loader=None,
location = loader.get_filename(name)
except ImportError:
pass
else:
location = _os.fspath(location)
# If the location is on the filesystem, but doesn't actually exist,
# we could return None here, indicating that the location is not
......
......@@ -5,6 +5,7 @@ machinery = test_util.import_importlib('importlib.machinery')
util = test_util.import_importlib('importlib.util')
import os.path
import pathlib
from test.support import CleanImport
import unittest
import sys
......@@ -659,6 +660,11 @@ class FactoryTests:
self.assertEqual(spec.cached, self.cached)
self.assertTrue(spec.has_location)
def test_spec_from_file_location_path_like_arg(self):
spec = self.util.spec_from_file_location(self.name,
pathlib.PurePath(self.path))
self.assertEqual(spec.origin, self.path)
def test_spec_from_file_location_default_without_location(self):
spec = self.util.spec_from_file_location(self.name)
......
......@@ -5,6 +5,7 @@ machinery = util.import_importlib('importlib.machinery')
importlib_util = util.import_importlib('importlib.util')
import os
import pathlib
import string
import sys
from test import support
......@@ -676,6 +677,15 @@ class PEP3147Tests:
self.util.cache_from_source('\\foo\\bar\\baz/qux.py', optimization=''),
'\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag))
@unittest.skipUnless(sys.implementation.cache_tag is not None,
'requires sys.implementation.cache_tag not be None')
def test_source_from_cache_path_like_arg(self):
path = pathlib.PurePath('foo', 'bar', 'baz', 'qux.py')
expect = os.path.join('foo', 'bar', 'baz', '__pycache__',
'qux.{}.pyc'.format(self.tag))
self.assertEqual(self.util.cache_from_source(path, optimization=''),
expect)
@unittest.skipUnless(sys.implementation.cache_tag is not None,
'requires sys.implementation.cache_tag to not be '
'None')
......@@ -738,6 +748,15 @@ class PEP3147Tests:
with self.assertRaises(ValueError):
self.util.source_from_cache(path)
@unittest.skipUnless(sys.implementation.cache_tag is not None,
'requires sys.implementation.cache_tag to not be '
'None')
def test_source_from_cache_path_like_arg(self):
path = pathlib.PurePath('foo', 'bar', 'baz', '__pycache__',
'qux.{}.pyc'.format(self.tag))
expect = os.path.join('foo', 'bar', 'baz', 'qux.py')
self.assertEqual(self.util.source_from_cache(path), expect)
(Frozen_PEP3147Tests,
Source_PEP3147Tests
......
......@@ -108,6 +108,8 @@ Library
- Issue #28005: Allow ImportErrors in encoding implementation to propagate.
- Issue #26667: Support path-like objects in importlib.util.
- Issue #27570: Avoid zero-length memcpy() etc calls with null source
pointers in the "ctypes" and "array" modules.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment