Skip to content

Commit fc0f794

Browse files
authored
A start on the documentation (python#30)
A first pass on the documentation, including usage and migration guides. API docs will be done in a follow up PR.
1 parent 8475c05 commit fc0f794

File tree

8 files changed

+438
-2
lines changed

8 files changed

+438
-2
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ matrix:
1111
- python: "3.7-dev"
1212

1313
install:
14-
- python3 -m pip install --upgrade mypy coverage
14+
- python3 -m pip install --upgrade mypy coverage sphinx
1515

1616
script:
1717
- python3 -m coverage run --rcfile=coverage.ini -m unittest discover
1818
- mypy --ignore-missing-imports importlib_resources
19+
- python3 setup.py build_sphinx
1920

2021
after_success:
2122
- bash <(curl -s https://codecov.io/bash)

importlib_resources/docs/_static/.ignoreme

Whitespace-only changes.

importlib_resources/docs/conf.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# flake8: noqa
5+
#
6+
# importlib_resources documentation build configuration file, created by
7+
# sphinx-quickstart on Thu Nov 30 10:21:00 2017.
8+
#
9+
# This file is execfile()d with the current directory set to its
10+
# containing dir.
11+
#
12+
# Note that not all possible configuration values are present in this
13+
# autogenerated file.
14+
#
15+
# All configuration values have a default; values that are commented out
16+
# serve to show the default.
17+
18+
# If extensions (or modules to document with autodoc) are in another directory,
19+
# add these directories to sys.path here. If the directory is relative to the
20+
# documentation root, use os.path.abspath to make it absolute, like shown here.
21+
#
22+
# import os
23+
# import sys
24+
# sys.path.insert(0, os.path.abspath('.'))
25+
26+
27+
# -- General configuration ------------------------------------------------
28+
29+
# If your documentation needs a minimal Sphinx version, state it here.
30+
#
31+
# needs_sphinx = '1.0'
32+
33+
# Add any Sphinx extension module names here, as strings. They can be
34+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
35+
# ones.
36+
extensions = ['sphinx.ext.autodoc',
37+
'sphinx.ext.doctest',
38+
'sphinx.ext.intersphinx',
39+
'sphinx.ext.coverage',
40+
'sphinx.ext.viewcode']
41+
42+
# Add any paths that contain templates here, relative to this directory.
43+
templates_path = ['_templates']
44+
45+
# The suffix(es) of source filenames.
46+
# You can specify multiple suffix as a list of string:
47+
#
48+
# source_suffix = ['.rst', '.md']
49+
source_suffix = '.rst'
50+
51+
# The master toctree document.
52+
master_doc = 'index'
53+
54+
# General information about the project.
55+
project = 'importlib_resources'
56+
copyright = '2017, Brett Cannon, Barry Warsaw'
57+
author = 'Brett Cannon, Barry Warsaw'
58+
59+
# The version info for the project you're documenting, acts as replacement for
60+
# |version| and |release|, also used in various other places throughout the
61+
# built documents.
62+
#
63+
# The short X.Y version.
64+
version = '0.1'
65+
# The full version, including alpha/beta/rc tags.
66+
release = '0.1'
67+
68+
# The language for content autogenerated by Sphinx. Refer to documentation
69+
# for a list of supported languages.
70+
#
71+
# This is also used if you do content translation via gettext catalogs.
72+
# Usually you set "language" from the command line for these cases.
73+
language = None
74+
75+
# List of patterns, relative to source directory, that match files and
76+
# directories to ignore when looking for source files.
77+
# This patterns also effect to html_static_path and html_extra_path
78+
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
79+
80+
# The name of the Pygments (syntax highlighting) style to use.
81+
pygments_style = 'sphinx'
82+
83+
# If true, `todo` and `todoList` produce output, else they produce nothing.
84+
todo_include_todos = False
85+
86+
87+
# -- Options for HTML output ----------------------------------------------
88+
89+
# The theme to use for HTML and HTML Help pages. See the documentation for
90+
# a list of builtin themes.
91+
#
92+
html_theme = 'alabaster'
93+
94+
# Theme options are theme-specific and customize the look and feel of a theme
95+
# further. For a list of options available for each theme, see the
96+
# documentation.
97+
#
98+
# html_theme_options = {}
99+
100+
# Add any paths that contain custom static files (such as style sheets) here,
101+
# relative to this directory. They are copied after the builtin static files,
102+
# so a file named "default.css" will overwrite the builtin "default.css".
103+
html_static_path = ['_static']
104+
105+
# Custom sidebar templates, must be a dictionary that maps document names
106+
# to template names.
107+
#
108+
# This is required for the alabaster theme
109+
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
110+
html_sidebars = {
111+
'**': [
112+
'relations.html', # needs 'show_related': True theme option to display
113+
'searchbox.html',
114+
]
115+
}
116+
117+
118+
# -- Options for HTMLHelp output ------------------------------------------
119+
120+
# Output file base name for HTML help builder.
121+
htmlhelp_basename = 'importlib_resourcesdoc'
122+
123+
124+
# -- Options for LaTeX output ---------------------------------------------
125+
126+
latex_elements = {
127+
# The paper size ('letterpaper' or 'a4paper').
128+
#
129+
# 'papersize': 'letterpaper',
130+
131+
# The font size ('10pt', '11pt' or '12pt').
132+
#
133+
# 'pointsize': '10pt',
134+
135+
# Additional stuff for the LaTeX preamble.
136+
#
137+
# 'preamble': '',
138+
139+
# Latex figure (float) alignment
140+
#
141+
# 'figure_align': 'htbp',
142+
}
143+
144+
# Grouping the document tree into LaTeX files. List of tuples
145+
# (source start file, target name, title,
146+
# author, documentclass [howto, manual, or own class]).
147+
latex_documents = [
148+
(master_doc, 'importlib_resources.tex', 'importlib\\_resources Documentation',
149+
'Brett Cannon, Barry Warsaw', 'manual'),
150+
]
151+
152+
153+
# -- Options for manual page output ---------------------------------------
154+
155+
# One entry per manual page. List of tuples
156+
# (source start file, name, description, authors, manual section).
157+
man_pages = [
158+
(master_doc, 'importlib_resources', 'importlib_resources Documentation',
159+
[author], 1)
160+
]
161+
162+
163+
# -- Options for Texinfo output -------------------------------------------
164+
165+
# Grouping the document tree into Texinfo files. List of tuples
166+
# (source start file, target name, title, author,
167+
# dir menu entry, description, category)
168+
texinfo_documents = [
169+
(master_doc, 'importlib_resources', 'importlib_resources Documentation',
170+
author, 'importlib_resources', 'One line description of project.',
171+
'Miscellaneous'),
172+
]
173+
174+
175+
176+
177+
# Example configuration for intersphinx: refer to the Python standard library.
178+
intersphinx_mapping = {
179+
'python': ('https://docs.python.org', None),
180+
}

importlib_resources/docs/index.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
================================
2+
Welcome to importlib_resources
3+
================================
4+
5+
``importlib_resources`` is a library which provides for access to *resources*
6+
in Python packages. It provides functionality similar to ``pkg_resources``
7+
`Basic Resource Access`_ API, but without all of the overhead and performance
8+
problems of ``pkg_resources``.
9+
10+
In our terminology, a *resource* is a file that is located within an
11+
importable `Python package`_. Resources can live on the file system, in a zip
12+
file, or in any place that has a loader_ supporting the appropriate API for
13+
reading resources. Directories are not resources.
14+
15+
``importlib_resources`` is a standalone version of the API available for users
16+
of Python 2.7, or Python 3.4 through 3.6. It is available in Python 3.7's
17+
standard library as ``importlib.resources``. Its API is currently
18+
`provisional`_.
19+
20+
This documentation includes a general :ref:`usage <using>` guide and a
21+
:ref:`migration` guide for projects which want to adopt
22+
``importlib_resources`` instead of ``pkg_resources``.
23+
24+
25+
.. toctree::
26+
:maxdepth: 2
27+
:caption: Contents:
28+
29+
using.rst
30+
migration.rst
31+
32+
33+
Indices and tables
34+
==================
35+
36+
* :ref:`genindex`
37+
* :ref:`modindex`
38+
* :ref:`search`
39+
40+
41+
.. _`Basic Resource Access`: http://setuptools.readthedocs.io/en/latest/pkg_resources.html#basic-resource-access
42+
.. _`provisional`: https://www.python.org/dev/peps/pep-0411/
43+
.. _`Python package`: https://docs.python.org/3/reference/import.html#packages
44+
.. _loader: https://docs.python.org/3/reference/import.html#finders-and-loaders
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
.. _migration:
2+
3+
=================
4+
Migration guide
5+
=================
6+
7+
The following guide will help you migrate common ``pkg_resources`` APIs to
8+
``importlib_resources``. Only a small number of the most common APIs are
9+
supported by ``importlib_resources``, so projects that use other features
10+
(e.g. entry points) will have to find other solutions.
11+
``importlib_resources`` primarily supports the following `basic resource
12+
access`_ APIs:
13+
14+
* ``pkg_resources.resource_filename()``
15+
* ``pkg_resources.resource_stream()``
16+
* ``pkg_resources.resource_string()``
17+
18+
Keep in mind that ``pkg_resources`` defines *resources* to include
19+
directories. ``importlib_resources`` does not treat directories as resources;
20+
since only file are allowed as resources, file names in the
21+
``importlib_resources`` API may *not* include path separators (e.g. slashes).
22+
23+
24+
resource_filename()
25+
===================
26+
27+
``resource_filename()`` is one of the more interesting APIs because it
28+
guarantees that the return value names a file on the file system. This means
29+
that if the resource is in a zip file, ``pkg_resources()`` will extract the
30+
file and return the name of the temporary file it created. The problem is
31+
that ``pkg_resources()`` also *implicitly* cleans up this temporary file,
32+
without control or its lifetime by the programmer.
33+
34+
``importlib_resources`` takes a different approach. Its equivalent API is the
35+
``path()`` function, which returns a context manager providing a
36+
:py:class:`pathlib.Path` object. This means users have both the flexibility
37+
and responsibility to manage the lifetime of the temporary file. Note though
38+
that if the resource is *already* on the file system, ``importlib_resources``
39+
still returns a context manager, but nothing needs to get cleaned up.
40+
41+
Here's an example from ``pkg_resources()``::
42+
43+
path = pkg_resources.resource_filename('my.package', 'resource.dat')
44+
45+
The best way to convert this is with the following idiom::
46+
47+
with importlib_resources.path('my.package', 'resource.dat') as path:
48+
# Do something with path. After the with-state exits, any temporary
49+
# file created will be immediately cleaned up.
50+
51+
That's all fine is you only need the file temporarily, but what if you need it
52+
to stick around for a while? One way of doing this is to use an
53+
:py:class:`contextlib.ExitStack` instance and manage the resource explicitly::
54+
55+
from contextlib import ExitStack
56+
file_manager = ExitStack()
57+
path = file_manager.enter_context(
58+
importlib_resources.path('my.package', 'resource.dat'))
59+
60+
Now ``path`` will continue to exist until you explicitly call
61+
``file_manager.close()``. What if you want the file to exist until the
62+
process exits, or you can't pass ``file_manager`` around in your code? Use an
63+
:py:mod:`atexit` handler::
64+
65+
import atexit
66+
file_manager = ExitStack()
67+
atexit.register(file_manager.close)
68+
path = file_manager.enter_context(
69+
importlib_resources.path('my.package', 'resource.dat'))
70+
71+
Assuming your Python interpreter exits gracefully, the temporary file will be
72+
cleaned up when Python exits.
73+
74+
75+
resource_stream()
76+
=================
77+
78+
``pkg_resources.resource_stream()`` returns a readable file-like object opened
79+
in binary mode. When you read from the returned file-like object, you get
80+
bytes. E.g.::
81+
82+
with pkg_resources.resource_stream('my.package', 'resource.dat') as fp:
83+
my_bytes = fp.read()
84+
85+
The equivalent code in ``importlib_resources`` is pretty straightforward::
86+
87+
with importlib_resources.open('my.package', 'resource.dat') as fp:
88+
my_bytes = fp.read()
89+
90+
91+
resource_string()
92+
=================
93+
94+
In Python 2, ``pkg_resources.resource_string()`` returns the contents of a
95+
resource as a ``str``. In Python 3, this function is a misnomer; it actually
96+
returns the contents of the named resource as ``bytes``. That's why the
97+
following example is often written for clarity as::
98+
99+
from pkg_resources import resource_string as resource_bytes
100+
contents = resource_bytes('my.package', 'resource.dat')
101+
102+
This can be easily rewritten like so::
103+
104+
contents = importlib_resources.read(
105+
'my.package', 'resource.dat', encoding=None)
106+
107+
The ``encoding=None`` argument is needed because by default ``read()`` returns
108+
a ``unicode`` in Python 2 or a ``str`` in Python 3, read and decoded with the
109+
``utf-8`` encoding.
110+
111+
112+
.. _`basic resource access`: http://setuptools.readthedocs.io/en/latest/pkg_resources.html#basic-resource-access

0 commit comments

Comments
 (0)