Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 36 additions & 27 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
if platform.system() == 'Windows':
import winreg

def is_configure_root() -> bool:
"""
Returns True if matlab folders should be configured at build time
"""
return os.environ.get('MATLAB_ENGINE_CONFIGURE_ROOT', 'true').lower() in ('true', '1')
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use env.var. to pass options, it could be replaced with extra build arguments



class _MatlabFinder(build_py):
"""
Private class that finds MATLAB on user's computer prior to package installation.
Expand Down Expand Up @@ -379,34 +386,36 @@ def run(self):
self.set_platform_and_arch()
self.set_python_version()

if self.platform == 'Windows':
matlab_root = self.get_matlab_root_from_windows_reg()
else:
if self.unix_default_install_exists():
matlab_root = self.DEFAULT_INSTALLS[self.platform]
if is_configure_root():
if self.platform == 'Windows':
matlab_root = self.get_matlab_root_from_windows_reg()
else:
path_dirs = self._create_path_list()
matlab_root = self.search_path_for_directory_unix(self.arch, path_dirs)
err_msg = self._err_msg_if_bad_matlab_root(matlab_root)
if err_msg:
if self.platform == 'Darwin':
if self.found_matlab_with_wrong_arch_in_default_install:
raise RuntimeError(
self.wrong_arch_in_default_install.format(
path1=self.found_matlab_with_wrong_arch_in_default_install,
matlab_arch=self._get_alternate_arch(),
python_arch=self.arch,
next_steps=self.next_steps))
if self.found_matlab_with_wrong_arch_in_path:
raise RuntimeError(
self.wrong_arch_in_path.format(
path1=self.found_matlab_with_wrong_arch_in_path,
matlab_arch=self._get_alternate_arch(),
python_arch=self.arch,
next_steps=self.next_steps))
raise RuntimeError(err_msg)
if self.unix_default_install_exists():
matlab_root = self.DEFAULT_INSTALLS[self.platform]
else:
path_dirs = self._create_path_list()
matlab_root = self.search_path_for_directory_unix(self.arch, path_dirs)
err_msg = self._err_msg_if_bad_matlab_root(matlab_root)
if err_msg:
if self.platform == 'Darwin':
if self.found_matlab_with_wrong_arch_in_default_install:
raise RuntimeError(
self.wrong_arch_in_default_install.format(
path1=self.found_matlab_with_wrong_arch_in_default_install,
matlab_arch=self._get_alternate_arch(),
python_arch=self.arch,
next_steps=self.next_steps))
if self.found_matlab_with_wrong_arch_in_path:
raise RuntimeError(
self.wrong_arch_in_path.format(
path1=self.found_matlab_with_wrong_arch_in_path,
matlab_arch=self._get_alternate_arch(),
python_arch=self.arch,
next_steps=self.next_steps))
raise RuntimeError(err_msg)

self.write_text_file(matlab_root)

self.write_text_file(matlab_root)
build_py.run(self)


Expand All @@ -427,7 +436,7 @@ def run(self):
package_dir={'': 'src'},
packages=find_packages(where="src"),
cmdclass={'build_py': _MatlabFinder},
package_data={'': ['_arch.txt']},
package_data={'': ['_arch.txt']} if is_configure_root() else {},
zip_safe=False,
project_urls={
'Documentation': 'https://www.mathworks.com/help/matlab/matlab-engine-for-python.html',
Expand Down
9 changes: 2 additions & 7 deletions src/matlab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import platform
import sys
import pkgutil
from . import _utils

__path__ = pkgutil.extend_path(__path__, __name__)
package_folder = os.path.dirname(os.path.realpath(__file__))
Expand Down Expand Up @@ -35,13 +36,7 @@ def add_dirs_to_path(bin_dir, engine_dir, extern_dir):
sys.path.insert(0, engine_dir)
sys.path.insert(0, extern_dir)

arch_file = os.path.join(package_folder, 'engine', '_arch.txt')
if not os.path.isfile(arch_file):
raise RuntimeError("The MATLAB Engine for Python install is corrupted. Please try to re-install.")

with open(arch_file, 'r') as root:
[arch, bin_folder, engine_folder, extern_bin] = [line.strip() for line in root.readlines()]

arch, bin_folder, engine_folder, extern_bin = _utils.get_path_info()

add_dirs_to_path(bin_folder, engine_folder, extern_bin)

Expand Down
58 changes: 58 additions & 0 deletions src/matlab/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import functools
import os
import platform
import shutil
from typing import Optional, NamedTuple


def _get_platform_arch() -> str:
system_name = platform.system()

if system_name == 'Windows':
return 'win64'
if system_name == 'Linux':
return 'glnxa64'
if system_name == 'Darwin':
if platform.mac_ver()[-1] == 'arm64':
return 'maca64'
return 'maci64'

raise RuntimeError(f"{system_name} is not a supported platform.")


def _get_matlab_root() -> Optional[str]:
"""Probe matlab root directory"""
matlab_command = shutil.which('matlab')
if not matlab_command:
return None
matlab_bin_dir = os.path.dirname(matlab_command)
matlab_root = os.path.normpath(os.path.join(matlab_bin_dir, os.pardir))
return matlab_root


class MatlabPathInfo(NamedTuple):
arch: str
bin_folder: str
engine_folder: str
extern_bin: str


@functools.cache
def get_path_info() -> MatlabPathInfo:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read _arch.txt and use which matlab as fallback.
This could be more involved and use the whole _MatlabFinder logic.

package_folder = os.path.dirname(os.path.realpath(__file__))
arch_file = os.path.join(package_folder, 'engine', '_arch.txt')
if os.path.isfile(arch_file):
with open(arch_file, 'r') as root:
[arch, bin_folder, engine_folder, extern_bin] = [line.strip() for line in root.readlines() if line.strip()]
return MatlabPathInfo(arch, bin_folder, engine_folder, extern_bin)

matlab_root = _get_matlab_root()
if matlab_root:
arch = _get_platform_arch()
bin_folder = os.path.join(matlab_root, 'bin', arch)
engine_folder = os.path.join(matlab_root, 'extern', 'engines', 'python', 'dist', 'matlab', 'engine', arch)
extern_bin = os.path.join(matlab_root, 'extern', 'bin', arch)
if os.path.isdir(bin_folder) and os.path.isdir(engine_folder) and os.path.isdir(extern_bin):
return MatlabPathInfo(arch, bin_folder, engine_folder, extern_bin)

raise RuntimeError("The MATLAB Engine for Python install is corrupted or matlab is not available. Please try to re-install.")
23 changes: 8 additions & 15 deletions src/matlab/engine/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import threading
import warnings

from .. import _utils

# UPDATE_IF_PYTHON_VERSION_ADDED_OR_REMOVED : search for this string in codebase
# when support for a Python version must be added or removed

Expand All @@ -50,8 +52,6 @@
'is %s' % _version)


_module_folder = os.path.dirname(os.path.realpath(__file__))
_arch_filename = os.path.join(_module_folder, "_arch.txt")
success = False
firstExceptionMessage = ''
secondExceptionMessage = ''
Expand All @@ -65,21 +65,14 @@

if firstExceptionMessage:
try:
_arch_file = open(_arch_filename,'r')
_lines = _arch_file.readlines()
[_arch, _bin_dir,_engine_dir, _extern_bin_dir] = [x.rstrip() for x in _lines if x.rstrip() != ""]
_arch_file.close()
sys.path.insert(0,_engine_dir)
sys.path.insert(0,_extern_bin_dir)

_envs = {'win32': 'PATH', 'win64': 'PATH'}
if _arch in _envs:
if _envs[_arch] in os.environ:
_env = os.environ[_envs[_arch]]
os.environ[_envs[_arch]] = _bin_dir + os.pathsep + os.environ[_envs[_arch]]
_path_info = _utils.get_path_info()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuse path info rather than re-reading the file

if _path_info.arch in _envs:
if _envs[_path_info.arch] in os.environ:
os.environ[_envs[_path_info.arch]] = _path_info.bin_folder + os.pathsep + os.environ[_envs[_path_info.arch]]
else:
os.environ[_envs[_arch]] = _bin_dir
os.add_dll_directory(_bin_dir)
os.environ[_envs[_path_info.arch]] = _path_info.bin_folder
os.add_dll_directory(_path_info.bin_folder)
if _PYTHONVERSION != '3_9' or _PYTHONVERSION != '3_10':
pythonengine = importlib.import_module("matlabengineforpython_abi3")
else:
Expand Down