Skip to content

Commit a5c7cc5

Browse files
committed
make addons utility work
1 parent ecf9516 commit a5c7cc5

File tree

2 files changed

+102
-8
lines changed

2 files changed

+102
-8
lines changed

redistricting/utils/addons.py

+50-8
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,41 @@
2222
* *
2323
***************************************************************************/
2424
"""
25+
import importlib
2526
import pathlib
2627
import subprocess
2728
import sys
2829

2930
from packaging.version import parse as parse_version
31+
from qgis.gui import QgisInterface
32+
from qgis.utils import iface
3033

31-
# from pip import main as pipmain
34+
iface: QgisInterface
35+
36+
37+
def install_vendor_dir():
38+
vendor_dir = pathlib.Path(__file__).parent.parent / "vendor"
39+
if vendor_dir.exists():
40+
sys.path.insert(0, str(vendor_dir.resolve()))
41+
42+
43+
def unload_module(mod: str):
44+
mod_prefix = f"{mod}."
45+
for m in list(sys.modules.keys()):
46+
if m == mod or m.startswith(mod_prefix):
47+
del sys.modules[m]
48+
49+
50+
def reload_modules():
51+
vendor_dir = pathlib.Path(__file__).parent.parent / "vendor"
52+
if vendor_dir.exists():
53+
for d in vendor_dir.iterdir():
54+
if d.suffix == '.py' or (d.is_dir() and (d / '__init__.py').exists()):
55+
mod = d.stem
56+
if mod in sys.modules:
57+
unload_module(mod)
58+
59+
importlib.import_module(mod)
3260

3361

3462
def python_executable():
@@ -42,26 +70,40 @@ def install_addon(pkg: str, *options):
4270
installdir = pathlib.Path(__file__).parent.parent / "vendor"
4371
if not installdir.exists():
4472
installdir.mkdir()
73+
install_vendor_dir()
74+
4575
if (installdir / pkg).exists():
4676
options = (*options, "--upgrade")
47-
subprocess.check_call([python_executable(), '-m', 'pip', 'install', '-t', str(installdir), *options, pkg])
48-
# pipmain(['install', '-t', str(installdir), *options, pkg])
77+
try:
78+
subprocess.check_call([python_executable(), '-m', 'pip', 'install', '-t', str(installdir), *options, pkg])
79+
except subprocess.CalledProcessError:
80+
iface.messageBar().pushWarning("Warning", f"Could not install addon {pkg}")
81+
return False
82+
83+
return True
4984

5085

5186
def install_pyogrio():
87+
# pylint: disable=import-outside-toplevel
5288
import geopandas
5389
if parse_version(geopandas.__version__) < parse_version('0.12.0'):
54-
install_addon('geopandas', "--no-deps")
90+
install_addon('geopandas')
5591
import shapely
5692
if parse_version(shapely.__version__) < parse_version('2.0.0'):
57-
install_addon('shapeley', "--no-deps")
93+
install_addon('shapeley')
5894

59-
install_addon('pyogrio', '--no-deps')
95+
install_addon('pyogrio')
96+
reload_modules()
6097

6198

6299
def install_pyarrow():
63-
install_addon('pyarrow', '--no-deps')
100+
install_addon('pyarrow')
101+
reload_modules()
64102

65103

66104
def install_gerrychain():
67-
install_addon('gerrychain', '--no-deps')
105+
install_addon('gerrychain==0.3.1')
106+
reload_modules()
107+
108+
109+
install_vendor_dir()

tests/unittests/utils/test_addons.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import pathlib
2+
import shutil
3+
import sys
4+
5+
import pytest
6+
7+
import redistricting
8+
9+
10+
# pylint: disable=import-outside-toplevel
11+
class TestAddons:
12+
@pytest.fixture
13+
def vendor_dir(self):
14+
d = pathlib.Path(redistricting.__file__).parent / "vendor"
15+
yield d
16+
17+
if d.exists():
18+
shutil.rmtree(d)
19+
20+
def test_install_pyogrio(self, vendor_dir):
21+
from redistricting.utils import addons
22+
23+
assert not vendor_dir.exists()
24+
25+
addons.install_pyogrio()
26+
27+
assert (vendor_dir / 'geopandas').exists()
28+
assert (vendor_dir / 'pyogrio').exists()
29+
assert 'geopandas' in sys.modules
30+
assert sys.modules['geopandas'].__spec__.origin == str(vendor_dir / 'geopandas' / '__init__.py')
31+
32+
def test_install_pyarrow(self, vendor_dir):
33+
from redistricting.utils import addons
34+
35+
assert not vendor_dir.exists()
36+
37+
addons.install_pyarrow()
38+
39+
assert (vendor_dir / 'pyarrow').exists()
40+
assert 'pyarrow' in sys.modules
41+
assert sys.modules['pyarrow'].__spec__.origin == str(vendor_dir / 'pyarrow' / '__init__.py')
42+
43+
def test_install_gerrychain(self, vendor_dir):
44+
from redistricting.utils import addons
45+
46+
assert not vendor_dir.exists()
47+
48+
addons.install_gerrychain()
49+
50+
assert (vendor_dir / 'gerrychain').exists()
51+
assert 'gerrychain' in sys.modules
52+
assert sys.modules['gerrychain'].__spec__.origin == str(vendor_dir / 'gerrychain' / '__init__.py')

0 commit comments

Comments
 (0)