diff options
author | Erik Skultety <eskultet@redhat.com> | 2023-03-13 15:14:20 +0100 |
---|---|---|
committer | Erik Skultety <eskultet@redhat.com> | 2023-03-14 11:14:35 +0100 |
commit | 92af40e31a8cb5cd6dbc26263a387ad14a89f9cf (patch) | |
tree | 4276430e055d99d093f954968f34080f0a2eeeef | |
parent | bda9c89cfce6d7ab0b1306c5e929500c0e8df2b1 (diff) | |
download | libvirt-ci-92af40e31a8cb5cd6dbc26263a387ad14a89f9cf.zip libvirt-ci-92af40e31a8cb5cd6dbc26263a387ad14a89f9cf.tar.gz libvirt-ci-92af40e31a8cb5cd6dbc26263a387ad14a89f9cf.tar.bz2 |
util: Add a 3.8 compatibility helper over importlib.resources.files
importlib.resources.files was introduced in Python 3.9. However, we
support Python 3.8+ which means that we need to add a compatibility
helper to query package resources properly. Normally we'd just go with
importlib.resources.path, but that API is lacks any kind of
practicality as it only accepts filenames as a resource, rejecting
relative paths, strings with directory delimiters or even directories.
So, if we want to iterate over a bunch of data files we ship along with
lcitool, we have to use other means to do that - get the imported
package directory and join that path with whatever we're looking for.
This solution doesn't work with resources not physically on the file
system, IOW with resources shipped as a ZIP which isn't our case
anyway.
Note that this patch can be reverted once we move onto 3.9+ in the
future.
Signed-off-by: Erik Skultety <eskultet@redhat.com>
-rw-r--r-- | lcitool/util.py | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/lcitool/util.py b/lcitool/util.py index da7fc8b..0267862 100644 --- a/lcitool/util.py +++ b/lcitool/util.py @@ -8,6 +8,7 @@ import copy import fnmatch import logging import os +import sys import platform import tempfile import textwrap @@ -205,6 +206,40 @@ def get_config_dir(): return Path(config_dir, "lcitool") +def package_resource(package, relpath): + """ + Backcompatibility helper to retrieve a package resource using importlib + + :param package: object conforming to importlib.resources.Package requirement + :param relpath: relative path to the actual resource (or directory) as + str or Path object + :returns: a Path object to the resource + """ + + from importlib import import_module, resources + + if hasattr(resources, "files"): + return Path(resources.files(package), relpath) + else: + # This is a horrible hack, it won't work for resources that don't exist + # on the file system (which should not be a problem for our use case), + # but it's needed because importlib.resources.path only accepts + # filenames for a 'Resource' [1]. What it means is that one cannot pass + # a path construct in 'relpath', because 'Resource' cannot contain + # path delimiters and also cannot be a directory, so we cannot use the + # method to construct base resource paths. + # [1] https://docs.python.org/3/library/importlib.resources.html?highlight=importlib%20resources#importlib.resources.path + # Instead, we'll extract the package path from ModuleSpec (loading the + # package first if needed) and then concatenate it with the 'relpath' + # + # TODO: Drop this helper once we move onto 3.9+ + if package not in sys.modules: + import_module(package) + + package_path = Path(sys.modules[package].__file__).parent + return Path(package_path, relpath) + + def merge_dict(source, dest): for key in source.keys(): if key not in dest: |