aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Skultety <eskultet@redhat.com>2023-03-13 15:14:20 +0100
committerErik Skultety <eskultet@redhat.com>2023-03-14 11:14:35 +0100
commit92af40e31a8cb5cd6dbc26263a387ad14a89f9cf (patch)
tree4276430e055d99d093f954968f34080f0a2eeeef
parentbda9c89cfce6d7ab0b1306c5e929500c0e8df2b1 (diff)
downloadlibvirt-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.py35
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: