Cope 2.5.0
My personal "standard library" of all the generally useful code I've written for various projects over the years
Loading...
Searching...
No Matches
imports.py
1"""
2Some useful abstractions of imports
3"""
4__version__ = '1.0.0'
5
6import importlib
7from varname import argname
8import sys
9
10def lazy_import(name:str):
11 """ Import a package upon being used, instead of immediately.
12 Useful for packages that want optional dependencies, like this one
13 copied from https://docs.python.org/3/library/importlib.html
14 If the package isn't installed or can't be found, it returns None
15 """
16 spec = importlib.util.find_spec(name)
17 if spec is None:
18 return None
19 loader = importlib.util.LazyLoader(spec.loader)
20 spec.loader = loader
21 module = importlib.util.module_from_spec(spec)
22 sys.modules[name] = module
23 loader.exec_module(module)
24 return module
25
26def ensure_imported(package, pip_name:str=...):
27 """ A decorator to ensure that `package` is not None, and if it is, raise an ImportError telling
28 the user what package needs to be installed. The package is assumed to be the same name as
29 the name of the variable passed to package. If it's not, be sure to set `pip_name` to the
30 proper value.
31
32 Note that `package` is either a module or None. It's meant to be used with the lazy_import()
33 function. This does no actual checking if the package is actually installed or not.
34
35 This decorator only works with functions. To use with a class, decorate __init__()
36 """
37 name = argname('package')
38 # If the installation name isn't specified, assume it's the same as the package name
39 if pip_name is Ellipsis:
40 pip_name = name
41
42 def decorator(func):
43 def decorated_func(*args, **kwargs):
44 if package is None:
45 raise ImportError(f'Function `{func.__name__}` requires the {name} package. Run `pip install {pip_name}` to resolve this error')
46 return func(*args, **kwargs)
47 return decorated_func
48 return decorator
49
50def try_import(name:str, pip_name:str=..., err:bool=False):
51 """ Try to import a package, if it exists. If `err` is True, then it raises an error telling the
52 user what package needs to be installed. The package is assumed to be the same name as
53 `name`. If it's not, be sure to set `pip_name` to the proper value. If `err` is False, it
54 just returns None.
55 If `err` is False, `pip_name` is not used.
56 """
57 try:
58 return __import__(name)
59 except ImportError as _err:
60 if err:
61 name = argname('name')
62 if pip_name is Ellipsis:
63 pip_name = name
64 raise ImportError(f"{name} package required. Run `pip install {pip_name}` to resolve this error'") from _err
65 else:
66 return None