feat: add util.resource_path()
function
need that now that we have configurable mako template paths
This commit is contained in:
parent
94868bbaa9
commit
b401fac04f
|
@ -27,6 +27,7 @@ classifiers = [
|
||||||
requires-python = ">= 3.8"
|
requires-python = ">= 3.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
'importlib-metadata; python_version < "3.10"',
|
'importlib-metadata; python_version < "3.10"',
|
||||||
|
"importlib_resources ; python_version < '3.9'",
|
||||||
"progress",
|
"progress",
|
||||||
"python-configuration",
|
"python-configuration",
|
||||||
]
|
]
|
||||||
|
|
|
@ -26,6 +26,7 @@ WuttJamaican - utilities
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
from uuid import uuid1
|
from uuid import uuid1
|
||||||
|
|
||||||
|
@ -264,3 +265,45 @@ def progress_loop(func, items, factory, message=None):
|
||||||
|
|
||||||
if progress:
|
if progress:
|
||||||
progress.finish()
|
progress.finish()
|
||||||
|
|
||||||
|
|
||||||
|
def resource_path(path):
|
||||||
|
"""
|
||||||
|
Returns the absolute file path for the given resource path.
|
||||||
|
|
||||||
|
A "resource path" is one which designates a python package name,
|
||||||
|
plus some path under that. For instance:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
wuttjamaican.email:templates
|
||||||
|
|
||||||
|
Assuming such a path should exist, the question is "where?"
|
||||||
|
|
||||||
|
So this function uses :mod:`python:importlib.resources` to locate
|
||||||
|
the path, possibly extracting the file(s) from a zipped package,
|
||||||
|
and returning the final path on disk.
|
||||||
|
|
||||||
|
It only does this if it detects it is needed, based on the given
|
||||||
|
``path`` argument. If that is already an absolute path then it
|
||||||
|
will be returned as-is.
|
||||||
|
|
||||||
|
:param path: Either a package resource specifier as shown above,
|
||||||
|
or regular file path.
|
||||||
|
|
||||||
|
:returns: Absolute file path to the resource.
|
||||||
|
"""
|
||||||
|
if not os.path.isabs(path) and ':' in path:
|
||||||
|
|
||||||
|
try:
|
||||||
|
# nb. these were added in python 3.9
|
||||||
|
from importlib.resources import files, as_file
|
||||||
|
except ImportError: # python < 3.9
|
||||||
|
from importlib_resources import files, as_file
|
||||||
|
|
||||||
|
package, filename = path.split(':')
|
||||||
|
ref = files(package) / filename
|
||||||
|
with as_file(ref) as path:
|
||||||
|
return str(path)
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
|
@ -277,3 +277,43 @@ class TestProgressLoop(TestCase):
|
||||||
# without progress
|
# without progress
|
||||||
mod.progress_loop(act, [1, 2, 3], None,
|
mod.progress_loop(act, [1, 2, 3], None,
|
||||||
message="whatever")
|
message="whatever")
|
||||||
|
|
||||||
|
|
||||||
|
class TestResourcePath(TestCase):
|
||||||
|
|
||||||
|
def test_basic(self):
|
||||||
|
|
||||||
|
# package spec is resolved to path
|
||||||
|
path = mod.resource_path('wuttjamaican:util.py')
|
||||||
|
self.assertTrue(path.endswith('wuttjamaican/util.py'))
|
||||||
|
|
||||||
|
# absolute path returned as-is
|
||||||
|
self.assertEqual(mod.resource_path('/tmp/doesnotexist.txt'), '/tmp/doesnotexist.txt')
|
||||||
|
|
||||||
|
def test_basic_pre_python_3_9(self):
|
||||||
|
|
||||||
|
# the goal here is to get coverage for code which would only
|
||||||
|
# run on python 3.8 and older, but we only need that coverage
|
||||||
|
# if we are currently testing python 3.9+
|
||||||
|
if sys.version_info.major == 3 and sys.version_info.minor < 9:
|
||||||
|
pytest.skip("this test is not relevant before python 3.9")
|
||||||
|
|
||||||
|
from importlib.resources import files, as_file
|
||||||
|
|
||||||
|
orig_import = __import__
|
||||||
|
|
||||||
|
def mock_import(name, globals=None, locals=None, fromlist=(), level=0):
|
||||||
|
if name == 'importlib.resources':
|
||||||
|
raise ImportError
|
||||||
|
if name == 'importlib_resources':
|
||||||
|
return MagicMock(files=files, as_file=as_file)
|
||||||
|
return orig_import(name, globals, locals, fromlist, level)
|
||||||
|
|
||||||
|
with patch('builtins.__import__', side_effect=mock_import):
|
||||||
|
|
||||||
|
# package spec is resolved to path
|
||||||
|
path = mod.resource_path('wuttjamaican:util.py')
|
||||||
|
self.assertTrue(path.endswith('wuttjamaican/util.py'))
|
||||||
|
|
||||||
|
# absolute path returned as-is
|
||||||
|
self.assertEqual(mod.resource_path('/tmp/doesnotexist.txt'), '/tmp/doesnotexist.txt')
|
||||||
|
|
Loading…
Reference in a new issue