Это происходит потому, что вы вызываете update_file_info , которая является частью системы асинхронного ввода-вывода Nautilus.Следовательно, он блокирует nautilus, если операции выполняются недостаточно быстро.
В вашем случае это усугубляется тем, что вы вызываете внешнюю программу, и это дорогостоящая операция.Обратите внимание, что update_file_info вызывается один раз для каждого файла.Если у вас есть 100 файлов, то вы будете вызывать внешнюю программу 100 раз, и Nautilus придется ждать каждого из них, прежде чем обрабатывать следующий.
Поскольку доступны nautilus-python 0.7 * update_file_info_full и cancel_update , что позволяет программировать асинхронные вызовы.Вы можете проверить документацию для Nautilus 0.7 для получения более подробной информации .
Стоит упомянуть, что это было ограничением только для nautilus-python, который ранее не предоставлял те методы, которые доступны в C.
РЕДАКТИРОВАТЬ : добавлена пара примеров.
Хитрость заключается в том, чтобы максимально ускорить процесс или сделать его асинхронным.
Пример 1. Вызоввнешняя программа
Используя упрощенную версию вашего кода, мы выполняем асинхронно, используя GObject.timeout_add_seconds in update_file_info_full .
from gi.repository import Nautilus, GObject
from urllib import unquote
from subprocess import Popen, PIPE
def getexiftool(filename):
options = '-fast2 -f -m -q -q -s3 -ExifIFD:DateTimeOriginal'
exiftool = Popen(['/usr/bin/exiftool'] + options.split() + [filename],
stdout=PIPE, stderr=PIPE)
output, errors = exiftool.communicate()
return output.split('\n')
class MyExtension(Nautilus.ColumnProvider, Nautilus.InfoProvider, GObject.GObject):
def __init__(self):
pass
def get_columns(self):
return (
Nautilus.Column(name='MyExif::DateTime',
attribute='Exif:Image:DateTime',
label='Date Original',
description='Data time original'
),
)
def update_file_info_full(self, provider, handle, closure, file_info):
if file_info.get_uri_scheme() != 'file':
return
filename = unquote(file_info.get_uri()[7:])
attr = ''
if file_info.get_mime_type() in ('image/jpeg', 'image/png'):
GObject.timeout_add_seconds(1, self.update_exif,
provider, handle, closure, file_info)
return Nautilus.OperationResult.IN_PROGRESS
file_info.add_string_attribute('Exif:Image:DateTime', attr)
return Nautilus.OperationResult.COMPLETE
def update_exif(self, provider, handle, closure, file_info):
filename = unquote(file_info.get_uri()[7:])
try:
data = getexiftool(filename)
attr = data[0]
except:
attr = ''
file_info.add_string_attribute('Exif:Image:DateTime', attr)
Nautilus.info_provider_update_complete_invoke(closure, provider,
handle, Nautilus.OperationResult.COMPLETE)
return False
Кодвыше не будет блокировать Nautilus, и если в представлении столбца доступен столбец «Дата оригинала», изображения JPEG и PNG будут показывать значение « unknown », и они будут медленно обновляться (подпроцессвызывается через 1 секунду).
Примеры 2. Использование библиотеки
Вместо того, чтобы вызывать внешнюю программу, лучше использовать библиотеку.Как показано в примере ниже:
from gi.repository import Nautilus, GObject
from urllib import unquote
import pyexiv2
class MyExtension(Nautilus.ColumnProvider, Nautilus.InfoProvider, GObject.GObject):
def __init__(self):
pass
def get_columns(self):
return (
Nautilus.Column(name='MyExif::DateTime',
attribute='Exif:Image:DateTime',
label='Date Original',
description='Data time original'
),
)
def update_file_info_full(self, provider, handle, closure, file_info):
if file_info.get_uri_scheme() != 'file':
return
filename = unquote(file_info.get_uri()[7:])
attr = ''
if file_info.get_mime_type() in ('image/jpeg', 'image/png'):
metadata = pyexiv2.ImageMetadata(filename)
metadata.read()
try:
tag = metadata['Exif.Image.DateTime'].value
attr = tag.strftime('%Y-%m-%d %H:%M')
except:
attr = ''
file_info.add_string_attribute('Exif:Image:DateTime', attr)
return Nautilus.OperationResult.COMPLETE
В конце концов, если процедура медленная, вам нужно будет сделать ее асинхронной (возможно, с использованием чего-то лучшего, чем GObject.timeout_add_seconds .
Наконец, что не менее важно, в моих примерах я использовал GObject Introspection (обычно для Nautilus 3), но его легко изменить, чтобы использовать модуль nautilus напрямую.