@@ -233,6 +233,7 @@ ABC hierarchy::
233233 | +-- MetaPathFinder
234234 | +-- PathEntryFinder
235235 +-- Loader
236+ +-- ResourceReader
236237 +-- ResourceLoader --------+
237238 +-- InspectLoader |
238239 +-- ExecutionLoader --+
@@ -468,6 +469,71 @@ ABC hierarchy::
468469 The import machinery now takes care of this automatically.
469470
470471
472+ .. class :: ResourceReader
473+
474+ An :term: `abstract base class ` for :term: `package `
475+ :term: `loaders <loader> ` to provide the ability to read
476+ *resources *.
477+
478+ From the perspective of this ABC, a *resource * is a binary
479+ artifact that is shipped within a package. Typically this is
480+ something like a data file that lives next to the ``__init__.py ``
481+ file of the package. The purpose of this class is to help abstract
482+ out the accessing of such data files so that it does not matter if
483+ the package and its data file(s) are stored in a e.g. zip file
484+ versus on the file system.
485+
486+ For any of methods of this class, a *resource * argument is
487+ expected to be a :term: `file-like object ` which represents
488+ conceptually just a file name. This means that no subdirectory
489+ paths should be included in the *resource * argument. This is
490+ because the location of the package that the loader is for acts
491+ as the "directory". Hence the metaphor for directories and file
492+ names is packages and resources, respectively. This is also why
493+ instances of this class are expected to directly correlate to
494+ a specific package (instead of potentially representing multiple
495+ packages or a module).
496+
497+ .. versionadded :: 3.7
498+
499+ .. abstractmethod :: open_resource(resource)
500+
501+ Returns an opened, :term: `file-like object ` for binary reading
502+ of the *resource *.
503+
504+ If the resource cannot be found, :exc: `FileNotFoundError ` is
505+ raised.
506+
507+ .. abstractmethod :: resource_path(resource)
508+
509+ Returns the file system path to the *resource *.
510+
511+ If the resource does not concretely exist on the file system,
512+ raise :exc: `FileNotFoundError `.
513+
514+ .. abstractmethod :: is_resource(name)
515+
516+ Returns ``True `` if the named *name * is considered a resource.
517+ :exc: `FileNotFoundError ` is raised if *name * does not exist.
518+
519+ .. abstractmethod :: contents()
520+
521+ Returns an :term: `iterator ` of strings over the contents of
522+ the package. Do note that it is not required that all names
523+ returned by the iterator be actual resources, e.g. it is
524+ acceptable to return names for which :meth: `is_resource ` would
525+ be false.
526+
527+ Allowing non-resource names to be returned is to allow for
528+ situations where how a package and its resources are stored
529+ are known a priori and the non-resource names would be useful.
530+ For instance, returning subdirectory names is allowed so that
531+ when it is known that the package and resources are stored on
532+ the file system then those subdirectory names can be used.
533+
534+ The abstract method returns an empty iterator.
535+
536+
471537.. class :: ResourceLoader
472538
473539 An abstract base class for a :term: `loader ` which implements the optional
0 commit comments