Skip to content

Commit 06be567

Browse files
Fix path behaviour, especially on Windows (#65)
1 parent 28a67dd commit 06be567

File tree

7 files changed

+42
-84
lines changed

7 files changed

+42
-84
lines changed

avo_xtb/config.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ def update_config(avo_input: dict):
192192
}
193193
# Pass back to Avogadro to display to user
194194
print(json.dumps(output))
195-
easyxtb.config["calcs_dir"] = str(easyxtb.CALCS_DIR)
195+
easyxtb.config["calcs_dir"] = str(easyxtb.CALCS_DIR.as_posix())
196196

197197
# Save any changes to binary paths
198198
for program in ["xtb", "crest"]:
@@ -204,7 +204,7 @@ def update_config(avo_input: dict):
204204
easyxtb.CREST_BIN = bin_path
205205
else:
206206
easyxtb.XTB_BIN = bin_path
207-
easyxtb.config[f"{program}_bin"] = str(bin_path)
207+
easyxtb.config[f"{program}_bin"] = str(bin_path.as_posix())
208208

209209
# Update other options that don't need coercing
210210
for option in ["n_proc", "energy_units", "solvent", "opt_lvl"]:

avo_xtb/install_crest.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pathlib import Path
1212

1313
from support import easyxtb
14-
from install_xtb import get_bin, link_bin
14+
from install_xtb import get_bin
1515

1616

1717
logger = logging.getLogger(__name__)
@@ -103,12 +103,10 @@
103103
except PermissionError:
104104
output = {"message": "Install directory is not writeable"}
105105
else:
106-
crest_folder = get_bin(crest_urls[platform.system()], install_dir)
107-
if crest_folder:
108-
link_bin(crest_folder/"crest")
106+
crest_bin = get_bin(crest_urls[platform.system()], install_dir)
109107
# Report success
110108
output = {
111-
"message": "CREST was successfully installed.\nPlease restart Avogadro."
109+
"message": f"CREST was successfully installed to\n{crest_bin}\nPlease restart Avogadro."
112110
}
113111

114112
# Pass result back to Avogadro to display to user

avo_xtb/install_xtb.py

+12-30
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def extract_tar(archive, target_dir) -> Path:
5656
return extracted
5757

5858

59-
def get_bin(url, install_dir):
59+
def get_bin(url: str, install_dir: Path) -> Path:
6060
# Don't install if url not valid
6161
if url[0:5] != "https":
6262
return
@@ -66,35 +66,19 @@ def get_bin(url, install_dir):
6666
folder = extract_zip(archive, install_dir)
6767
else:
6868
folder = extract_tar(archive, install_dir)
69+
# Remove archive
70+
archive.unlink()
6971
# Rename unzipped folder to a non-versioned name we have chosen
72+
# Store appropriate path to binary
7073
if "crest" in folder.name:
71-
folder = folder.rename(folder.with_name("crest-dist"))
74+
folder = folder.rename(folder.with_name("crest"))
75+
bin_name = "crest.exe" if platform.system() == "Windows" else "crest"
76+
bin_path = folder/bin_name
7277
else:
7378
folder = folder.rename(folder.with_name("xtb-dist"))
74-
# Remove archive
75-
archive.unlink()
76-
return folder
77-
78-
79-
def link_bin(bin_path):
80-
if "crest" in bin_path.name:
81-
bin_name = "crest"
82-
else:
83-
bin_name = "xtb"
84-
# Check Windows
85-
if bin_path.with_suffix(".exe").exists():
86-
bin_path = bin_path.with_suffix(".exe")
87-
# Link
88-
if bin_name == "xtb":
89-
easyxtb.XTB_BIN = easyxtb.BIN_DIR / bin_path.name
90-
easyxtb.XTB_BIN.symlink_to(bin_path)
91-
elif bin_name == "crest":
92-
easyxtb.CREST_BIN = easyxtb.BIN_DIR / bin_path.name
93-
easyxtb.CREST_BIN.symlink_to(bin_path)
94-
# Add to config
95-
easyxtb.config[f"{bin_name}_bin"] = str(easyxtb.BIN_DIR / bin_path.name)
96-
# Save config
97-
easyxtb.configuration.save_config()
79+
bin_name = "xtb.exe" if platform.system() == "Windows" else "xtb"
80+
bin_path = folder/f"bin/{bin_name}"
81+
return bin_path
9882

9983

10084
if __name__ == "__main__":
@@ -175,12 +159,10 @@ def link_bin(bin_path):
175159
except PermissionError:
176160
output = {"message": "Install directory is not writeable"}
177161
else:
178-
xtb_folder = get_bin(xtb_urls[platform.system()], install_dir)
179-
if xtb_folder:
180-
link_bin(xtb_folder/"bin/xtb")
162+
xtb_bin = get_bin(xtb_urls[platform.system()], install_dir)
181163
# Report success
182164
output = {
183-
"message": "xtb was successfully installed.\nPlease restart Avogadro."
165+
"message": f"xtb was successfully installed to\n{xtb_bin}\nPlease restart Avogadro."
184166
}
185167

186168
# Pass result back to Avogadro to display to user

easyxtb/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "easyxtb"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
description = "A Python API for xtb (and CREST)."
55
readme = "README.md"
66
requires-python = ">=3.10"

easyxtb/src/easyxtb/configuration.py

+22-44
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def save_config():
113113

114114
# Current version of package
115115
# Hard code for now, obviously not ideal though
116-
easyxtb_VERSION = "0.8.0"
116+
easyxtb_VERSION = "0.8.1"
117117

118118
def update_config():
119119
"""Ensure that any config options added in later versions of the package are in
@@ -145,45 +145,23 @@ def update_config():
145145
BIN_DIR.mkdir(parents=True, exist_ok=True)
146146

147147

148-
def find_xtb() -> Path | None:
149-
"""Return path to xtb binary as Path object, or None."""
150-
if (BIN_DIR/"xtb").exists():
151-
# Normal binary or symlink to it
152-
xtb = BIN_DIR/"xtb"
153-
elif (BIN_DIR/"xtb.exe").exists():
154-
# Windows
155-
xtb = BIN_DIR/"xtb.exe"
156-
elif (BIN_DIR/"xtb-dist").exists():
157-
# Whole xtb distribution folder with nested binary directory
158-
xtb = BIN_DIR/"xtb-dist/bin/xtb"
159-
# Or, on Windows
160-
if platform.system() == "Windows":
161-
xtb = xtb.with_suffix(".exe")
162-
elif which("xtb") is not None:
163-
# Check PATH
164-
xtb = Path(which("xtb"))
165-
else:
166-
xtb = None
167-
logger.debug(f"xtb binary location determined to be: {xtb}")
168-
return xtb
169-
170-
171-
def find_crest() -> Path | None:
172-
"""Return path to crest binary as Path object, or None"""
173-
if (BIN_DIR/"crest").exists():
174-
crest = BIN_DIR/"crest"
175-
elif (BIN_DIR/"crest/crest").exists():
176-
crest = BIN_DIR/"crest/crest"
177-
# Currently there is no Windows binary for crest but let's assume there will be
178-
elif (BIN_DIR/"crest.exe").exists():
179-
crest = BIN_DIR/"crest.exe"
180-
elif which("crest") is not None:
181-
# Check PATH
182-
crest = Path(which("crest"))
183-
else:
184-
crest = None
185-
logger.debug(f"crest binary location determined to be: {crest}")
186-
return crest
148+
def find_bin(program: str) -> Path | None:
149+
"""Return path to xtb or CREST binary as Path object, or None."""
150+
bin_name = f"{program}.exe" if platform.system() == "Windows" else program
151+
bin_path = None
152+
for possible_location in [
153+
BIN_DIR/bin_name, # Normal binary or symlink to it
154+
BIN_DIR/program/bin_name, # Old layout for xtb, current for CREST
155+
BIN_DIR/f"{program}-dist/bin/{bin_name}", # Whole xtb distribution folder with nested binary directory
156+
]:
157+
if possible_location.exists() and not possible_location.is_dir():
158+
bin_path = possible_location
159+
break
160+
# Otherwise check the PATH
161+
if not bin_path and which(bin_name) is not None:
162+
bin_path = Path(which(bin_name))
163+
logger.debug(f"{bin_name} binary location determined to be: {bin_path}")
164+
return bin_path
187165

188166

189167
# Initialize and find the various binaries
@@ -194,15 +172,15 @@ def find_crest() -> Path | None:
194172
if "xtb_bin" in config:
195173
XTB_BIN = Path(config["xtb_bin"])
196174
if not XTB_BIN.exists():
197-
XTB_BIN = find_xtb()
175+
XTB_BIN = find_bin("xtb")
198176
else:
199-
XTB_BIN = find_xtb()
177+
XTB_BIN = find_bin("xtb")
200178
if "crest_bin" in config:
201179
CREST_BIN = Path(config["crest_bin"])
202180
if not CREST_BIN.exists():
203-
CREST_BIN = find_crest()
181+
CREST_BIN = find_bin("crest")
204182
else:
205-
CREST_BIN = find_crest()
183+
CREST_BIN = find_bin("crest")
206184

207185

208186
if XTB_BIN is not None:

plugin.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"author": "Matthew J. Milner",
3-
"version": "0.8.0",
3+
"version": "0.8.1",
44
"url": "https://github.com/matterhorn103/avo_xtb",
55
"name": "avo_xtb",
66
"description": "Access the power of xtb through the Avogadro interface.",

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "avo_xtb"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
description = "A convenient interface to xtb (and CREST) in Avogadro 2"
55
readme = "README.md"
66
requires-python = ">=3.10"

0 commit comments

Comments
 (0)