Python Mlab — невозможно импортировать имя find_available_releases

Я новичок в Python. Я пытаюсь запустить MATLAB изнутри Python, используя пакет mlab. Я следил за руководством на веб-сайте и ввел это в командной строке Python:

from mlab.releases import latest_release

Ошибка, которую я получил, была:

cannot import name find_available_releases

Вроде под matlabcom.py не было функции find_available_releases.

Могу ли я узнать, знает ли кто-нибудь, как это решить? Благодарю вас!

PS: я использую Windows 7, MATLAB 2012a и Python 2.7.


person KSS    schedule 18.12.2013    source источник
comment
Я использую Windows 7, MATLAB 2012a и Python 2.7.   -  person KSS    schedule 18.12.2013
comment
Вы пытаетесь выполнить скрипт Python из Matlab?   -  person m_power    schedule 14.02.2014
comment
@m_power Он пытается запустить MATLAB из Python.   -  person Dennis Jaheruddin    schedule 08.05.2014


Ответы (2)


Я просмотрел код, и я не думаю, что весь README файл и его документация соответствуют тому, что на самом деле реализовано. По большей части он скопирован из исходного проекта mlabwrap.

Это сбивает с толку, потому что mlabwrap реализован с использованием модуля расширения C для взаимодействия с API MATLAB Engine. Однако код mlab, похоже, заменил эту часть чистой реализацией Python в качестве бэкэнда MATLAB-bridge. Источник: "Dana Pe'er Lab. " и использует два разных метода взаимодействия с MATLAB в зависимости от платформы (COM/ActiveX в Windows и каналы в Linux/Mac).


Теперь, когда мы понимаем, как реализован бэкенд, можно приступить к рассмотрению ошибки импорта.

Примечание: часть кода для Linux/Mac пытается найти исполняемый файл MATLAB в некоторых жестко закодированных фиксированных местах и ​​позволяет выбирать между различными версиями.

Однако вы работаете в Windows, и код на самом деле не реализует какой-либо способ выбора между выпусками MATLAB для этой платформы (поэтому все методы, такие как discover_location и find_available_releases, бесполезны в Windows). В итоге COM-объект создается как:

self.client = win32com.client.Dispatch('matlab.application')

Как объяснено здесь, ProgID matlab.application не зависит от версии и будет просто использовать то, что было зарегистрирован как сервер MATLAB COM по умолчанию. Мы можем явно указать, какую версию MATLAB мы хотим (при условии, что у вас несколько установок), например, matlab.application.8.3 выберет MATLAB R2014a.

Таким образом, чтобы исправить код, IMO самым простым способом было бы избавиться от всей этой логики о нескольких версиях MATLAB (в часть кода для Windows), и просто создайте COM-объект MATLAB как есть. Я не пробовал, но не думаю, что это слишком сложно... Удачи!


РЕДАКТИРОВАТЬ:

Я загружаю модуль, и мне удалось заставить его работать в Windows (я использую Python 2.7.6 и MATLAB R2014a). Вот изменения:

$ git diff
diff --git a/src/mlab/matlabcom.py b/src/mlab/matlabcom.py
index 93f075c..da1c6fa 100644
--- a/src/mlab/matlabcom.py
+++ b/src/mlab/matlabcom.py
@@ -21,6 +21,11 @@ except:
   print 'win32com in missing, please install it'
   raise

+def find_available_releases():
+    # report we have all versions
+    return [('R%d%s' % (y,v), '')
+        for y in range(2006,2015) for v in ('a','b')]
+
 def discover_location(matlab_release):
     pass

@@ -62,7 +67,7 @@ class MatlabCom(object):
     """
     self._check_open()
     try:
-      self.eval('quit();')
+      pass    #self.eval('quit();')
     except:
       pass
     del self.client
diff --git a/src/mlab/mlabraw.py b/src/mlab/mlabraw.py
index 3471362..16e0e2b 100644
--- a/src/mlab/mlabraw.py
+++ b/src/mlab/mlabraw.py
@@ -42,6 +42,7 @@ def open():
     if is_win:
         ret = MatlabConnection()
         ret.open()
+        return ret
     else:
         if settings.MATLAB_PATH != 'guess':
             matlab_path = settings.MATLAB_PATH + '/bin/matlab'
diff --git a/src/mlab/releases.py b/src/mlab/releases.py
index d792b12..9d6cf5d 100644
--- a/src/mlab/releases.py
+++ b/src/mlab/releases.py
@@ -88,7 +88,7 @@ class MatlabVersions(dict):
         # Make it a module
         sys.modules['mlab.releases.' + matlab_release] = instance
         sys.modules['matlab'] = instance
-        return MlabWrap()
+        return instance

     def pick_latest_release(self):
         return get_latest_release(self._available_releases)

Сначала я добавил недостающую функцию find_available_releases. Я сделал так, чтобы он сообщал, что доступны все версии MATLAB (как я объяснил выше, это не имеет большого значения из-за способа создания COM-объекта). Еще лучшим решением было бы обнаружение установленных/зарегистрированных версий MATLAB с помощью реестра Windows (проверьте ключи HKCR\Matlab.Application.X.Y и следуйте их CLSID в HKCR\CLSID). Таким образом, вы действительно можете выбирать, какую версию запускать.

Я также исправил две несвязанные ошибки (в одной автор забыл возвращаемое значение функции, а в другой дважды создавался объект-оболочка без необходимости).

Примечание. Во время тестирования может быть быстрее НЕ запускать/закрывать экземпляр MATLAB каждый раз, когда вызывается скрипт. Вот почему я прокомментировал self.eval('quit();') в функции close. Таким образом, вы можете запустить MATLAB, используя matlab.exe -automation (выполните это только один раз), а затем повторно использовать сеанс, не закрывая его. Просто убейте процесс, когда закончите :)

Вот пример Python для тестирования модуля (я также показываю сравнение с NumPy/SciPy/Matplotlib):

test_mlab.py

# could be anything from: latest_release, R2014b, ..., R2006a
# makes no difference :)
from mlab.releases import R2014a as matlab

# show MATLAB version
print "MATLAB version: ", matlab.version()
print matlab.matlabroot()

# compute SVD of a NumPy array
import numpy as np
A = np.random.rand(5, 5)
U, S, V = matlab.svd(A, nout=3)
print "S = \n", matlab.diag(S)

# compare MATLAB's SVD against Scipy's SVD
U, S, V = np.linalg.svd(A)
print S

# 3d plot in MATLAB
X, Y, Z = matlab.peaks(nout=3)
matlab.figure(1)
matlab.surf(X, Y, Z)
matlab.title('Peaks')
matlab.xlabel('X')
matlab.ylabel('Y')
matlab.zlabel('Z')

# compare against matplotlib surface plot
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='jet')
ax.view_init(30.0, 232.5)
plt.title('Peaks')
plt.xlabel('X')
plt.ylabel('Y')
ax.set_zlabel('Z')
plt.show()

Вот что я получаю:

C:\>python test_mlab.py
MATLAB version: 8.3.0.532 (R2014a)
C:\Program Files\MATLAB\R2014a
S =
[[ 2.41632007]
 [ 0.78527851]
 [ 0.44582117]
 [ 0.29086795]
 [ 0.00552422]]
[ 2.41632007  0.78527851  0.44582117  0.29086795  0.00552422]

matlab_peaks_surfmatplotlib_peaks_surf


РЕДАКТИРОВАТЬ2:

Указанные выше изменения были приняты и объединены в mlab.

person Amro    schedule 15.07.2014
comment
Да, Windows и обнаружение путей через com/registry просто не реализованы. Некоторое время был в моем списке дел. Извините. Поскольку это так важно для людей, я применю патч как можно скорее. Кстати, это в основном копия оригинальной mlabwrap, которая также снята с производства. - person Yauhen Yakimovich; 26.08.2014
comment
Применил патч к 1.1.3 после тестирования на Windows и Linux. Обновлен PyPI, теперь он должен содержаться в «pip install mlab». +1 за хорошую работу. Спасибо. - person Yauhen Yakimovich; 26.08.2014
comment
@YauhenYakimovich: Спасибо за участие в беседе! Я буду рад протестировать его в Windows, когда вы примените исправление обнаружения реестра. Что касается описания, возможно, было бы полезно, если бы вы добавили примечание в верхней части примерно такого содержания: Ниже приведен исходный файл README из проекта mlabwrap. Большинство из них по-прежнему применимы, но базовая реализация отличается (COM/Pipes заменили использование MATLAB Engine API). - person Amro; 26.08.2014

Вы правы, говоря, что find_available_releases() не написан. 2 способа решить эту проблему

  • Проверьте код в Linux и поработайте над ним (Вы работаете над Windows!)
  • Измените код, как показано ниже

Добавьте следующую функцию в matlabcom.py, как в matlabpipe.py.

def find_available_releases():
    global _RELEASES
    if not _RELEASES:
        _RELEASES = list(_list_releases())
    return _RELEASES

Если вы видите файл mlabraw.py, следующий код даст вам четкое представление, почему я это говорю!

import sys
is_win = 'win' in sys.platform
if is_win:
    from matlabcom import MatlabCom as MatlabConnection
    from matlabcom import MatlabError as error
    from matlabcom import discover_location, find_available_releases
    from matlabcom import WindowsMatlabReleaseNotFound as MatlabReleaseNotFound
else:
    from matlabpipe import MatlabPipe as MatlabConnection
    from matlabpipe import MatlabError as error
    from matlabpipe import discover_location, find_available_releases
    from matlabpipe import UnixMatlabReleaseNotFound as MatlabReleaseNotFound
person attaboyabhipro    schedule 15.07.2014