Re: Loading Resources From a Python Module/Package
Donald Stufft <[email protected]> Fri, 30 Jan 2015 19:52:50 -0500
| Newsgroups | gmane.comp.python.import |
|---|---|
| Message-ID | <[email protected]> |
> On Jan 30, 2015, at 7:18 PM, Paul Moore <[email protected]> wrote: > > On 30 January 2015 at 23:37, Donald Stufft <[email protected]> wrote: >> A. What do people think about pkgutil.get_data_filename and >> Loader.get_data_filename? > > Sounds reasonable. It's a relatively rare, but useful use case. One > possible issue, though, would people assume that if they get a > filename it'd be writeable? For the filesystem loader it would be, but > that would break subtly (writes work but would get discarded) for > loaders that don't have a native get_data_filename. I don’t think you can assume it’s writeable since that’ll break in a lot of common cases even with the filesystem loader since often times things in the filesystem will be installed in the system and users won’t have permissions to write to them anyways. > > Related question - how would the temp files be cleaned up? At exit? My patch registers an atexit handler that cleans up the temporary files yea. > >> B. What do people think about modifying Loader.get_data so it can support >> relative filenames instead of the calling code needing to handle that? > > I'd have to think about that one, but in principle it seems reasonable. > > While we're extending the loaders, a far more commonly requested > feature would be to list available data files. At the moment, code can > only load data from known paths, which is not ideal. While it's > unrelated to the original proposal, it makes sense if we're changing > the spec of loaders to do it in one go, rather than having multiple > iterations. Well both pkgutil.get_data and pkgutil.get_data_filename have parallels in the pkg_resources library for similar reasons. If we want to extend this to more things it might make sense to take a look at what all exists there currently: resource_exists(package_or_requirement, resource_name) Does the named resource exist? Return True or False accordingly. resource_stream(package_or_requirement, resource_name) Return a readable file-like object for the specified resource; it may be an actual file, a StringIO, or some similar object. The stream is in “binary mode”, in the sense that whatever bytes are in the resource will be read as-is. resource_string(package_or_requirement, resource_name) Return the specified resource as a string. The resource is read in binary fashion, such that the returned string contains exactly the bytes that are stored in the resource. resource_isdir(package_or_requirement, resource_name) Is the named resource a directory? Return True or False accordingly. resource_listdir(package_or_requirement, resource_name) List the contents of the named resource directory, just like os.listdir except that it works even if the resource is in a zipfile. resource_filename(package_or_requirement, resource_name) Sometimes, it is not sufficient to access a resource in string or stream form, and a true filesystem filename is needed. In such cases, you can use this method (or module-level function) to obtain a filename for a resource. If the resource is in an archive distribution (such as a zipped egg), it will be extracted to a cache directory, and the filename within the cache will be returned. If the named resource is a directory, then all resources within that directory (including subdirectories) are also extracted. If the named resource is a C extension or “eager resource” (see the setuptools documentation for details), then all C extensions and eager resources are extracted at the same time. See https://pythonhosted.org/setuptools/pkg_resources.html#basic-resource-access and https://pythonhosted.org/setuptools/pkg_resources.html#resource-extraction Obviously the similar functions here are: * pkgutil.get_data is pkg_resources.resource_string * pkgutil.get_data_filename is pkg_resources.resource_filename The major difference being that pkg_resource.resource_filename will extract to a cache directory (controllable with an environment variable or programatically) and won't clean up the extracted files. This means that they are (by default) extracted once per user and reused between extractions. I felt like it made more sense to just extract to a temporary location (even though this is less performant) in the stdlib. That leaves: * resource_exists * resource_stream * resource_isdir * resource_listdir Which can be done via pkg_resources but not via the standard library, I don't have a major opinion on whether or not the standard library should do all of them but I don't think it would hurt if it did. Another interesting question if we're going to add more methods is where they should all live. As far as I know pkgutil.get_data predates the importlib module. Perhaps deprecating pkgutil.get_data and adding a importlib.resources module which supports functions like: * get_bytes(package, resource) * get_stream(package, resource) * get_filename(package, resource) * exists(package, resource) * isdir(package, resource) * listdir(package, resource) Changing the names (particular get_data -> get_bytes) could also provide the mechanism for allowing relative files and deprecating the "you must pass in a full file path to the Loader()" behavior since the get_data method could be left alone and a new get_bytes method could be added. This would mean people can do things like: import importlib.resources import socket import ssl context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context.verify_mode = ssl.CERT_REQUIRED context.check_hostname = True context.load_verify_locations( cafile=importlib.resources.get_filename("certifi", "cacert.pem"), ) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com') ssl_sock.connect(('www.verisign.com', 443)) --- Donald Stufft PGP: 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA _______________________________________________ Import-SIG mailing list [email protected] https://mail.python.org/mailman/listinfo/import-sig