Python TypeError при загрузке объекта с использованием Dill

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

Со стороны dill.dump(file) претензий нет:

In [1]: import echonest.remix.audio as audio

In [2]: import dill

In [3]: audiofile = audio.LocalAudioFile("/Users/path/Track01.mp3")
en-ffmpeg -i "/Users/path/audio/Track01.mp3" -y -ac 2 -ar 44100 "/var/folders/X2/X2KGhecyG0aQhzRDohJqtU+++TI/-Tmp-/tmpWbonbH.wav"
Computed MD5 of file is b3820c166a014b7fb8abe15f42bbf26e
Probing for existing analysis

In [4]: with open('audio_object_dill.pkl', 'wb') as f:
   ...:     dill.dump(audiofile, f)
   ...:  

In [5]: 

Но пытаюсь загрузить файл .pkl:

In [1]: import dill

In [2]: with open('audio_object_dill.pkl', 'rb') as f:
   ...:     audio_object = dill.load(f)
   ...:  

Возвращает следующую ошибку:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-203b696a7d73> in <module>()
      1 with open('audio_object_dill.pkl', 'rb') as f:
----> 2     audio_object = dill.load(f)
      3 

/Users/mikekilmer/Envs/GLITCH/lib/python2.7/site-packages/dill-0.2.2.dev-py2.7.egg/dill/dill.pyc in load(file)
    185     pik = Unpickler(file)
    186     pik._main_module = _main_module
--> 187     obj = pik.load()
    188     if type(obj).__module__ == _main_module.__name__: # point obj class to main
    189         try: obj.__class__ == getattr(pik._main_module, type(obj).__name__)

/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.pyc in load(self)
    856             while 1:
    857                 key = read(1)
--> 858                 dispatch[key](self)
    859         except _Stop, stopinst:
    860             return stopinst.value

/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.pyc in load_newobj(self)
   1081         args = self.stack.pop()
   1082         cls = self.stack[-1]
-> 1083         obj = cls.__new__(cls, *args)
   1084         self.stack[-1] = obj
   1085     dispatch[NEWOBJ] = load_newobj

TypeError: __new__() takes at least 2 arguments (1 given)

AudioObject намного сложнее (и больше), чем class object, для которого выполняются вышеуказанные вызовы (из SO answer), и мне неясно, нужно ли мне отправлять второй аргумент через dill, и если да, то каким будет этот аргумент или как определить, есть ли какой-либо подход к травлению пригодны для данного конкретного объекта.

Немного осмотрим сам объект:

In [4]: for k, v in vars(audiofile).items():
...:     print k, v
...: 

возвращает:

is_local False
defer False
numChannels 2
verbose True
endindex 13627008
analysis <echonest.remix.audio.AudioAnalysis object at 0x103c61bd0>
filename /Users/mikekilmer/Envs/GLITCH/glitcher/audio/Track01.mp3
convertedfile /var/folders/X2/X2KGhecyG0aQhzRDohJqtU+++TI/-Tmp-/tmp9ADD_Z.wav
sampleRate 44100
data [[0 0]
 [0 0]
 [0 0]
 ..., 
 [0 0]
 [0 0]
 [0 0]]

И audiofile.analysis, кажется, содержит атрибут с именем audiofile.analysis.source, который содержит (или явно указывает на) audiofile.analysis.source.analysis


person MikeiLL    schedule 28.08.2014    source источник
comment
более подробно изучить документацию, которая находится по адресу pypi.python.org/pypi/dill.   -  person MikeiLL    schedule 28.08.2014
comment
Читаю в docs.python.org/2/library/pickle.html этот файл должен иметь два метода. Может быть, файл, который я сохраняю, имеет только один метод, и это отсутствие второго аргумента, который нарушает cls.__new__(cls, *args)   -  person MikeiLL    schedule 28.08.2014
comment
Можно ли использовать echonest API, чтобы опробовать его в случае необходимости? В любом случае, есть несколько вещей, которые вы можете попытаться выяснить, что происходит. Во-первых, поскольку это класс, вы можете попробовать переключить byref в dill.dumps, чтобы переключить выделение класса по ссылке. Если это не сработает, попробуйте включить dill.detect.trace(True), чтобы увидеть внутренние контрольные точки в (де)сериализации. Вы также можете просмотреть методы в dill.detect, такие как badobjects, которые могут помочь диагностировать, что происходит. Похоже на несоответствие __getstate__ и __setstate__, что было бы странно.   -  person Mike McKerns    schedule 28.08.2014
comment
Это @MikeMcKerns. echonest.com. Два соответствующих модуля доступны через developer.ehonest.com, и я поделился процедурой по адресу: mzoo.org/getting-the-python-ehonest-remix-package-running< /а>. Являются pypi.python.org/pypi/dill, trac.mystic.cacr.caltech.edu/project/pathos/wiki/dill и документы о рассоле в основном объем материала для чтения, на который я должен обратить внимание (при выполнении приведенных выше рекомендаций)?   -  person MikeiLL    schedule 28.08.2014
comment
Если бы использование with open('audio_object_dill.pkl', 'wb') as f: byref было установлено таким образом, dill.dump(audiofile, f, byref=True) с False было бы значением по умолчанию, верно? dill.load результаты совпадают. Введено dill.detect.trace(True) до dill.dump результатов вызова: pastebin.com/V0fA7aVJ. Наконец, dill.detect.badobjects(audiofile) возвращает <echonest.remix.audio.LocalAudioFile at 0x103ebc710>. Хм.   -  person MikeiLL    schedule 28.08.2014
comment
Прежде всего, вау, это крутая упаковка. Немного покопавшись, dill.detect.children(audiofile, echonest.remix.audio.LocalAudioFile) выдает, что имя 'ehonest' не определено - на самом деле просто нужно было вызвать его с помощью модуля переменной, который был импортирован с помощью: dill.detect.children(audiofile, audio.LocalAudioFile), что дает наш старый друг [<echonest.remix.audio.LocalAudioFile at 0x103ebc710>]   -  person MikeiLL    schedule 28.08.2014
comment
Ждать! По-видимому, в API есть встроенный метод: echonest.github.io/remix/apidocs/   -  person MikeiLL    schedule 28.08.2014
comment
Боже, какой ужасный trace у вас в pastebin. Да, это все материалы для чтения на dill, к сожалению. Кстати, вы должны попробовать badobjects(audiofile, depth=1) -- это позволит вам копаться в каждом объекте, даже в том, что не удалось. Также проверьте это как пример того, что может сделать обнаружение укропа. stackoverflow .com/questions/10082241/ stackoverflow.com/questions/25241139/   -  person Mike McKerns    schedule 29.08.2014
comment
Определенно играл с плохими объектами (аудиофайл, глубина = 1), но он зависает, давая f(self, obj) # Call unbound method with explicit self в методе pickle save.   -  person MikeiLL    schedule 29.08.2014
comment
Так встроенное сохранение работало из API? Похоже, это может быть то, что они ожидают от вас (вместо dump напрямую), и может быть поэтому кажется, что load ожидает чего-то другого.   -  person Mike McKerns    schedule 30.08.2014
comment
да. Встроенное сохранение прекрасно работает и перезагружается с помощью укропа.   -  person MikeiLL    schedule 30.08.2014
comment
тогда вы должны ответить на свой вопрос (вопросы), так как другие могут столкнуться с тем же.   -  person Mike McKerns    schedule 30.08.2014
comment
или я отвечу на него. кто-то должен, поэтому людям не нужно копаться в комментариях.   -  person Mike McKerns    schedule 01.09.2014
comment
@MikeMcKerns Я отвечу на него с нетерпением жду возможности. Возможно завтра и спасибо за напоминание. Были мысли о. Я думаю, что у меня может быть даже S.O. Cred, чтобы добавить echonest в качестве ключевого слова.   -  person MikeiLL    schedule 01.09.2014


Ответы (1)


В данном случае ответ лежит внутри самого модуля.

Класс LocalAudioFile предоставляет (и каждый из его экземпляров может для этого использовать) свой собственный метод save, вызываемый через LocalAudioFile.save или, что более вероятно, the_audio_object_instance.save.

В случае файла .mp3 экземпляр LocalAudioFile состоит из указателя на временный файл .wav, который является распакованной версией .mp3, вместе с целой кучей данных анализа, которые возвращаются из исходного аудиофайла после его взаимодействия с (в Интернете) Echonest API.

LocalAudioFile.save вызывает shutil.copyfile(path_to_wave, wav_path) для сохранения файл .wav с тем же именем и путем, что и исходный файл, связанный с аудиообъектом, и возвращает ошибку, если файл уже существует. Он вызывает pickle.dump(self, f) для сохранения данных анализа в файл также в каталоге, из которого был вызван исходный файл аудиообъекта.

Объект LocalAudioFile можно повторно ввести просто через pickle.load().

Вот сеанс iPython, в котором я использовал dill, который является очень полезной оболочкой или интерфейсом, который предлагает большинство стандартных методов pickle, а также кучу других:

audiofile = audio.LocalAudioFile("/Users/mikekilmer/Envs/GLITCH/glitcher/audio/Track01.mp3")

In [1]: import echonest.remix.audio as audio

In [2]: import dill
# create the audio_file object
In [3]: audiofile = audio.LocalAudioFile("/Users/mikekilmer/Envs/GLITCH/glitcher/audio/Track01.mp3")
en-ffmpeg -i "/Users/path/audio/Track01.mp3" -y -ac 2 -ar 44100 "/var/folders/X2/X2KGhecyG0aQhzRDohJqtU+++TI/-Tmp-/tmp_3Ei0_.wav"
Computed MD5 of file is b3820c166a014b7fb8abe15f42bbf26e
Probing for existing analysis
#call the LocalAudioFile save method
In [4]: audiofile.save()
Saving analysis to local file /Users/path/audio/Track01.mp3.analysis.en
#confirm the object is valid by calling it's duration method
In [5]: audiofile.duration
Out[5]: 308.96
#delete the object - there's probably a "correct" way to do this
in [6]: audiofile = 0
#confirm it's no longer an audio_object
In [7]: audiofile.duration
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-12-04baaeda53a4> in <module>()
----> 1 audiofile2.duration

AttributeError: 'int' object has no attribute 'duration'


#open the pickled version (using dill)
In [8]: with open('/Users/path/audio/Track01.mp3.analysis.en') as f:
   ....:     audiofile = dill.load(f)
   ....:     
#confirm it's a valid LocalAudioFile object
In [8]: audiofile.duration
Out[8]: 308.96

Echonest — очень надежный API, а пакет remix предоставляет массу функций. Небольшой список соответствующих ссылок собран здесь.

person MikeiLL    schedule 02.09.2014