Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions Doc/library/pkgutil.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,24 +151,48 @@ support.
:meth:`get_data <importlib.abc.ResourceLoader.get_data>` API. The
*package* argument should be the name of a package, in standard module format
(``foo.bar``). The *resource* argument should be in the form of a relative
filename, using ``/`` as the path separator. The parent directory name
``..`` is not allowed, and nor is a rooted name (starting with a ``/``).
filename, using ``/`` as the path separator.

The function returns a binary string that is the contents of the specified
resource.

This function uses the :term:`loader` method
:func:`~importlib.abc.FileLoader.get_data`
to support modules installed in the filesystem, but also in zip files,
databases, or elsewhere.

For packages located in the filesystem, which have already been imported,
this is the rough equivalent of::

d = os.path.dirname(sys.modules[package].__file__)
data = open(os.path.join(d, resource), 'rb').read()

Like the :func:`open` function, :func:`!get_data` can follow parent
directories (``../``) and absolute paths (starting with ``/`` or ``C:/``,
for example).
It can open compilation/installation artifacts like ``.py`` and ``.pyc``
files or files with :func:`reserved filenames <os.path.isreserved>`.
To be compatible with non-filesystem loaders, avoid using these features.

.. warning::

This function is intended for trusted input.
It does not verify that *resource* "belongs" to *package*.

If you use a user-provided *resource* path, consider verifying it.
For example, require an alphanumeric filename with a known extension, or
install and check a list of known resources.

If the package cannot be located or loaded, or it uses a :term:`loader`
which does not support :meth:`get_data <importlib.abc.ResourceLoader.get_data>`,
then ``None`` is returned. In particular, the :term:`loader` for
:term:`namespace packages <namespace package>` does not support
:meth:`get_data <importlib.abc.ResourceLoader.get_data>`.

.. seealso::

The :mod:`importlib.resources` module provides structured access to
module resources.

.. function:: resolve_name(name)

Expand Down
3 changes: 0 additions & 3 deletions Lib/pkgutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,6 @@ def get_data(package, resource):
# signature - an os.path format "filename" starting with the dirname of
# the package's __file__
parts = resource.split('/')
if os.path.isabs(resource) or '..' in parts:
raise ValueError("resource must be a relative path with no "
"parent directory components")
parts.insert(0, os.path.dirname(mod.__file__))
resource_name = os.path.join(*parts)
return loader.get_data(resource_name)
Expand Down
19 changes: 0 additions & 19 deletions Lib/test/test_pkgutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,6 @@ def test_getdata_filesys(self):

del sys.modules[pkg]

def test_getdata_path_traversal(self):
pkg = 'test_getdata_traversal'

# Make a package with some resources
package_dir = os.path.join(self.dirname, pkg)
os.mkdir(package_dir)
# Empty init.py
f = open(os.path.join(package_dir, '__init__.py'), "wb")
f.close()

with self.assertRaises(ValueError):
pkgutil.get_data(pkg, '../../../etc/passwd')
with self.assertRaises(ValueError):
pkgutil.get_data(pkg, 'sub/../../../etc/passwd')
with self.assertRaises(ValueError):
pkgutil.get_data(pkg, os.path.abspath('/etc/passwd'))

del sys.modules[pkg]

def test_getdata_zipfile(self):
zip = 'test_getdata_zipfile.zip'
pkg = 'test_getdata_zipfile'
Expand Down

This file was deleted.

Loading