Skip to content

Commit

Permalink
Fix: Windows TBB path logic fails if BridgeStan is not yet downloaded (
Browse files Browse the repository at this point in the history
…#149)

* Test import without

* Fix name

* Move Windows path logic later in runtime

* Fix: store whether path has already been set properly

* Move 'global' keyword

* Remove from compile step

* Rename to windows_dll_path_setup

* Try to fix example on Windows

* Use abspath

* In fact, just always store abspath
  • Loading branch information
WardBrian committed Jun 30, 2023
1 parent 90eff7d commit 41ffee8
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 52 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ jobs:
pip install pytest
pip install .
- name: Test import
run: |
python -c "import bridgestan"
- name: Run tests
run: |
cd python/
Expand Down Expand Up @@ -155,6 +159,12 @@ jobs:
path: ./test_models/
key: ${{ hashFiles('**/*.stan', 'src/*', 'stan/src/stan/version.hpp', 'Makefile') }}-${{ matrix.os }}-v${{ env.CACHE_VERSION }}

- name: Check import
run: |
cd julia/
julia --project=. -e "using Pkg; Pkg.instantiate()"
julia --project=. -e "using BridgeStan"
- name: Run tests
run: |
cd julia/
Expand Down
47 changes: 0 additions & 47 deletions python/bridgestan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,3 @@
from .model import StanModel

__all__ = ["StanModel", "set_bridgestan_path", "compile_model"]

import platform as _plt

if _plt.system() == "Windows":

def _windows_path_setup():
"""Add tbb.dll to %PATH% on Windows."""
import os
import subprocess
import warnings

from .compile import get_bridgestan_path

try:
out = subprocess.run(
["where.exe", "tbb.dll"], check=True, capture_output=True
)
tbb_path = os.path.dirname(out.stdout.decode().splitlines()[0])
os.add_dll_directory(tbb_path)
except:
tbb_path = os.path.join(
get_bridgestan_path(), "stan", "lib", "stan_math", "lib", "tbb"
)
os.environ["PATH"] = tbb_path + ";" + os.environ["PATH"]
os.add_dll_directory(tbb_path)

try:
out = subprocess.run(
[
"where.exe",
"libwinpthread-1.dll",
"libgcc_s_seh-1.dll",
"libstdc++-6.dll",
],
check=True,
capture_output=True,
)
mingw_dir = os.path.dirname(out.stdout.decode().splitlines()[0])
os.add_dll_directory(mingw_dir)
except:
# no default location
warnings.warn(
"Unable to find MinGW's DLL location. Loading BridgeStan models may fail.",
RuntimeWarning,
)

_windows_path_setup()
61 changes: 58 additions & 3 deletions python/bridgestan/compile.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import os
import platform
import subprocess
import warnings
from pathlib import Path
from typing import List
import warnings

from .__version import __version__
from .download import CURRENT_BRIDGESTAN, HOME_BRIDGESTAN, get_bridgestan_src
Expand All @@ -26,11 +26,14 @@ def verify_bridgestan_path(path: str) -> None:
)


IS_WINDOWS = platform.system() == "Windows"
WINDOWS_PATH_SET = False

PYTHON_FOLDER = Path(__file__).parent.parent

MAKE = os.getenv(
"MAKE",
"make" if platform.system() != "Windows" else "mingw32-make",
"make" if not IS_WINDOWS else "mingw32-make",
)


Expand All @@ -44,6 +47,7 @@ def set_bridgestan_path(path: str) -> None:
of this package (which, assuming a source installation, corresponds
to the repository root).
"""
path = os.path.abspath(path)
verify_bridgestan_path(path)
os.environ["BRIDGESTAN"] = path

Expand Down Expand Up @@ -99,7 +103,6 @@ def compile_model(
:raises RuntimeError: If compilation fails.
"""
verify_bridgestan_path(get_bridgestan_path())

file_path = Path(stan_file).resolve()
validate_readable(str(file_path))
if file_path.suffix != ".stan":
Expand All @@ -125,3 +128,55 @@ def compile_model(

raise RuntimeError(error)
return output


def windows_dll_path_setup():
"""Add tbb.dll to %PATH% on Windows."""
global WINDOWS_PATH_SET
if IS_WINDOWS and not WINDOWS_PATH_SET:
try:
out = subprocess.run(
["where.exe", "tbb.dll"], check=True, capture_output=True
)
tbb_path = os.path.dirname(out.stdout.decode().splitlines()[0])
os.add_dll_directory(tbb_path)
except:
try:
tbb_path = os.path.abspath(
os.path.join(
get_bridgestan_path(), "stan", "lib", "stan_math", "lib", "tbb"
)
)
os.environ["PATH"] = tbb_path + ";" + os.environ["PATH"]
os.add_dll_directory(tbb_path)
WINDOWS_PATH_SET = True
except:
warnings.warn(
"Unable to set path to TBB's DLL. Loading BridgeStan models may fail. "
f"Tried path '{tbb_path}'",
RuntimeWarning,
)
WINDOWS_PATH_SET = False
try:
out = subprocess.run(
[
"where.exe",
"libwinpthread-1.dll",
"libgcc_s_seh-1.dll",
"libstdc++-6.dll",
],
check=True,
capture_output=True,
)
mingw_dir = os.path.abspath(
os.path.dirname(out.stdout.decode().splitlines()[0])
)
os.add_dll_directory(mingw_dir)
WINDOWS_PATH_SET &= True
except:
# no default location
warnings.warn(
"Unable to find MinGW's DLL location. Loading BridgeStan models may fail.",
RuntimeWarning,
)
WINDOWS_PATH_SET = False
3 changes: 2 additions & 1 deletion python/bridgestan/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from numpy.ctypeslib import ndpointer

from .__version import __version_info__
from .compile import compile_model
from .compile import windows_dll_path_setup, compile_model
from .util import validate_readable

FloatArray = npt.NDArray[np.float64]
Expand Down Expand Up @@ -67,6 +67,7 @@ def __init__(
with open(model_data, "r") as f:
model_data = f.read()

windows_dll_path_setup()
self.lib_path = model_lib
self.stanlib = ctypes.CDLL(self.lib_path)

Expand Down
2 changes: 1 addition & 1 deletion python/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import bridgestan as bs

bs.set_bridgestan_path("../")
bs.set_bridgestan_path("..")

stan = "../test_models/bernoulli/bernoulli.stan"
data = "../test_models/bernoulli/bernoulli.data.json"
Expand Down

0 comments on commit 41ffee8

Please sign in to comment.