Skip to content

Commit

Permalink
Add API documentation (python#34)
Browse files Browse the repository at this point in the history
API documentation.

Closes python#16
  • Loading branch information
warsaw authored Dec 4, 2017
1 parent a7e8a66 commit 3e9cda3
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 21 deletions.
107 changes: 107 additions & 0 deletions importlib_resources/docs/api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
=========================
importlib_resources API
=========================

``importlib_resources`` exposes a small number of functions, and it references
a limited number of types, both as arguments to functions and as return types.


Types
=====

.. py:class:: Package
``Package`` types are defined as ``Union[ModuleType, str]``. This means
that where the function describes accepting a ``Package``, you can pass in
either a module or a string. Note that in Python 2, the module object
*must* have a ``__path__`` attribute, while in Python 3, the module object
must have a resolvable ``__spec__.submodule_search_locations`` that is not
``None``.

.. py:class:: FileName
This type describes the resource names passed into the various functions
in this package. For Python 3.6 and later, this is defined as
``Union[str, os.PathLike]``. For earlier versions (which don't have
``os.PathLike``), this is defined as ``str``.


Functions
=========

.. py:function:: importlib_resources.open(package, file_name, encoding=None, errors=None)
Open for reading the resource named ``file_name`` within the ``package``
package. By default, the resource is opened for reading in binary mode.
With a non-``None`` ``encoding`` argument, the resource is opened in text
mode, with ``errors`` having the same meaning as for built-in
:py:func:`open`.

:param package: A package name or module object. See above for the API
that such module objects must support.
:type package: ``Package``
:param file_name: The name of the resource to open within ``package``.
``file_name`` may not contain path separators and it may
not have sub-resources (i.e. it cannot be a directory).
:type file_name: ``FileName``
:param encoding: When ``None``, the resource is opened in binary mode.
When an encoding is given, the resource is opened in text
mode. ``encoding`` has the same meaning as with
:py:func:`open`.
:type encoding: str
:param errors: This parameter is ignored when ``encoding`` is ``None``.
Otherwise it has the same meaning as with :py:func:`open`.
:type errors: str
:returns: an I/O stream open for reading.
:rtype: ``typing.IO``


.. py:function:: importlib_resources.read(package, file_name, encoding='utf-8', errors='strict')
Read and return the contents of the resource named ``file_name`` within
the ``package`` package. By default, the contents are read in UTF-8 and
returned as a ``str`` (in Python 3 - ``unicode`` in Python 2). With
``encoding`` set to ``None``, the resource contents are read in binary
mode and returned as ``bytes``.

:param package: A package name or module object. See above for the API
that such module objects must support.
:type package: ``Package``
:param file_name: The name of the resource to read within ``package``.
``file_name`` may not contain path separators and it may
not have sub-resources (i.e. it cannot be a directory).
:type file_name: ``FileName``
:param encoding: When ``None``, the resource is read in binary mode.
When an encoding is given, the resource is read in text
mode. ``encoding`` has the same meaning as with
:py:func:`open`.
:type encoding: str
:param errors: This parameter is ignored when ``encoding`` is ``None``.
Otherwise it has the same meaning as with :py:func:`open`.
:type errors: str
:returns: the contents of the resource.
:rtype: ``bytes`` or ``str``

.. py:function:: importlib_resources.path(package, file_name)
Return the path to the resource as an actual file system path. This
function returns a `context manager`_ for use in a ``with``-statement.
The context manager provides a :py:class:`pathlib.Path` object.

Exiting the context manager cleans up any temporary file created when the
resource needs to be extracted from e.g. a zip file.

:param package: A package name or module object. See above for the API
that such module objects must support.
:type package: ``Package``
:param file_name: The name of the resource to read within ``package``.
``file_name`` may not contain path separators and it may
not have sub-resources (i.e. it cannot be a directory).
:type file_name: ``FileName``
:returns: A context manager for use in a ``with``-statement. Entering
the context manager provides a :py:class:`pathlib.Path`
object.
:rtype: context manager providing a :py:class:`pathlib.Path` object


.. _`context manager`: https://docs.python.org/3/library/stdtypes.html#typecontextmanager
2 changes: 1 addition & 1 deletion importlib_resources/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,5 @@

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'py': ('https://docs.python.org/3/', None),
'python': ('https://docs.python.org/3', None),
}
3 changes: 2 additions & 1 deletion importlib_resources/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ standard library as ``importlib.resources``. Its API is currently
`provisional`_.

This documentation includes a general :ref:`usage <using>` guide and a
:ref:`migration` guide for projects which want to adopt
:ref:`migration <migration>` guide for projects that want to adopt
``importlib_resources`` instead of ``pkg_resources``.


Expand All @@ -28,6 +28,7 @@ This documentation includes a general :ref:`usage <using>` guide and a

using.rst
migration.rst
api.rst


Indices and tables
Expand Down
10 changes: 5 additions & 5 deletions importlib_resources/docs/migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ access`_ APIs:

Keep in mind that ``pkg_resources`` defines *resources* to include
directories. ``importlib_resources`` does not treat directories as resources;
since only file are allowed as resources, file names in the
since only files are allowed as resources, file names in the
``importlib_resources`` API may *not* include path separators (e.g. slashes).


Expand All @@ -29,7 +29,7 @@ guarantees that the return value names a file on the file system. This means
that if the resource is in a zip file, ``pkg_resources()`` will extract the
file and return the name of the temporary file it created. The problem is
that ``pkg_resources()`` also *implicitly* cleans up this temporary file,
without control or its lifetime by the programmer.
without control over its lifetime by the programmer.

``importlib_resources`` takes a different approach. Its equivalent API is the
``path()`` function, which returns a context manager providing a
Expand All @@ -45,10 +45,10 @@ Here's an example from ``pkg_resources()``::
The best way to convert this is with the following idiom::

with importlib_resources.path('my.package', 'resource.dat') as path:
# Do something with path. After the with-state exits, any temporary
# file created will be immediately cleaned up.
# Do something with path. After the with-statement exits, any
# temporary file created will be immediately cleaned up.

That's all fine is you only need the file temporarily, but what if you need it
That's all fine if you only need the file temporarily, but what if you need it
to stick around for a while? One way of doing this is to use an
:py:class:`contextlib.ExitStack` instance and manage the resource explicitly::

Expand Down
31 changes: 17 additions & 14 deletions importlib_resources/docs/using.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,34 @@ Your test could read the data file by doing something like::
eml = fp.read()

But there's a problem with this! The use of ``__file__`` doesn't work if your
package lives inside a zip file, since in that case, this code does not live
on the file system.
package lives inside a zip file, since in that case this code does not live on
the file system.

You could use the `pkg_resources API`_ like so::

# In Python 3, resource_string() actually returns bytes!
from pkg_resources import resource_string as resource_bytes
eml = resource_bytes('email.tests.data', 'message.eml').decode('utf-8')

This requires you to make both ``email/tests`` and ``email/tests/data`` to be
Python packages, by placing empty ``__init__.py`` files in those directories.
This requires you to make Python packages of both ``email/tests`` and
``email/tests/data``, by placing an empty ``__init__.py`` files in each of
those directories.

**This is a requirement for ``importlib_resources`` too!**

The problem with this is that, depending on the structure of your package,
``pkg_resources`` can be very inefficient even to just import.
``pkg_resources`` is a sort of grab-bag of APIs and functionalities, and to
support all of this, it sometimes has to do a ton of work at import time,
e.g. to scan every package on your ``sys.path``. This can have a serious
negative impact on things like command line startup time for Python implement
commands.
The problem with the ``pkg_resources`` approach is that, depending on the
structure of your package, ``pkg_resources`` can be very inefficient even to
just import. ``pkg_resources`` is a sort of grab-bag of APIs and
functionalities, and to support all of this, it sometimes has to do a ton of
work at import time, e.g. to scan every package on your ``sys.path``. This
can have a serious negative impact on things like command line startup time
for Python implement commands.

``importlib_resources`` solves this by being built entirely on the back of the
stdlib :py:mod:`importlib`. This makes it very fast, by taking advantage of
all the efficiencies in Python's import system. The equivalent code using
``importlib_resources`` would look like::
stdlib :py:mod:`importlib`. By taking advantage of all the efficiencies in
Python's import system, and the fact that it's built into Python, using
``importlib_resources`` can be much more performant. The equivalent code
using ``importlib_resources`` would look like::

from importlib_resources import read
# Reads contents with UTF-8 encoding and returns str.
Expand Down

0 comments on commit 3e9cda3

Please sign in to comment.