Ошибка при работе с Excel с использованием Python
В то время как мой скрипт обновляется один Excel одновременно, если я собираюсь выполнить любую другую работу вручную с другой ошибкой Excel происходит, я использую диспетчеризацию
from win32com.client import Dispatch
excel = Dispatch('Excel.Application')
excel.Visible = True
file_name="file_name.xls"
workbook = excel.Workbooks.Open(file_name)
workBook = excel.ActiveWorkbook
sheet=workbook.Sheets(sheetno)
Я получаю сообщение об ошибке (com_error(-2147418111, "Вызов отклонен вызываемым абонентом". Нет, Нет)
Есть ли способ преодолеть это.. я могу обновить другой Excel без получения ошибки..
5 ответов
Я столкнулся с этой же проблемой недавно. Хотя может показаться, что может быть несколько основных причин, моя ситуация возникала из-за того, что Python выполнял последующие вызовы слишком быстро, чтобы Excel не отставал, особенно при обновлении внешних запросов. Я исправил эту прерывистую ошибку "Вызов отклонен вызываемым пользователем", вставив time.sleep()
между большинством моих вызовов и увеличением аргумента сна для любых вызовов, которые являются особенно продолжительными (обычно между 7-15 секундами). Это дает Excel время для выполнения каждой команды, прежде чем Python выпустит дополнительные команды.
Эта ошибка возникает из-за того, что вызываемый вами COM-объект отклоняет внешний вызов, если он уже обрабатывает другую операцию. Там нет асинхронной обработки вызовов, и поведение может показаться случайным.
В зависимости от операции вы увидите либо pythoncom.com_error, либо pywintypes.com_error. Простой (если не элегантный) способ обойти это - заключить ваши вызовы в COM-объект с помощью try-exc и, если вы получили одну из этих ошибок доступа, повторите ваш вызов.
Для получения дополнительной информации см. Раздел "Обработка ошибок" главы 12, отрывок из Python Programming на Win32 Марка Хэммонда и Энди Робинсона (O'Reilly 2000).
Также есть некоторая полезная информация о Excel в блоге Сью Кам Онна "Программирование на Python с помощью Excel, как преодолеть COM_error из файла python, созданного makepy".
Я боролся с той же проблемой, но теперь я нашел решение, которое работает для меня до сих пор.
Я создал класс ComWrapper, в который обертываю COM-объект Excel. Он автоматически оборачивает каждый вложенный объект и вызов в ComWrapper и разворачивает их, когда они используются в качестве аргументов для вызовов функций или присваиваний обернутым объектам. Оболочка работает, перехватывая исключения "Вызов отклонен вызываемым абонентом" и повторяя вызов, пока не истечет время ожидания, указанное в верхней части. Если время ожидания истекло, исключение, наконец, выбрасывается за пределы объекта-оболочки.
Вызовы функций для обернутых объектов автоматически оборачиваются функцией _com_call_wrapper, в которой и происходит волшебство.
Чтобы заставить его работать, просто оберните com-объект из Dispatch с помощью ComWrapper, а затем используйте его как обычно, как в нижней части кода. Прокомментируйте, если есть проблемы.
import win32com.client
from pywintypes import com_error
import time
import logging
_DELAY = 0.05 # seconds
_TIMEOUT = 60.0 # seconds
def _com_call_wrapper(f, *args, **kwargs):
"""
COMWrapper support function.
Repeats calls when 'Call was rejected by callee.' exception occurs.
"""
# Unwrap inputs
args = [arg._wrapped_object if isinstance(arg, ComWrapper) else arg for arg in args]
kwargs = dict([(key, value._wrapped_object)
if isinstance(value, ComWrapper)
else (key, value)
for key, value in dict(kwargs).items()])
start_time = None
while True:
try:
result = f(*args, **kwargs)
except com_error as e:
if e.strerror == 'Call was rejected by callee.':
if start_time is None:
start_time = time.time()
logging.warning('Call was rejected by callee.')
elif time.time() - start_time >= _TIMEOUT:
raise
time.sleep(_DELAY)
continue
raise
break
if isinstance(result, win32com.client.CDispatch) or callable(result):
return ComWrapper(result)
return result
class ComWrapper(object):
"""
Class to wrap COM objects to repeat calls when 'Call was rejected by callee.' exception occurs.
"""
def __init__(self, wrapped_object):
assert isinstance(wrapped_object, win32com.client.CDispatch) or callable(wrapped_object)
self.__dict__['_wrapped_object'] = wrapped_object
def __getattr__(self, item):
return _com_call_wrapper(self._wrapped_object.__getattr__, item)
def __getitem__(self, item):
return _com_call_wrapper(self._wrapped_object.__getitem__, item)
def __setattr__(self, key, value):
_com_call_wrapper(self._wrapped_object.__setattr__, key, value)
def __setitem__(self, key, value):
_com_call_wrapper(self._wrapped_object.__setitem__, key, value)
def __call__(self, *args, **kwargs):
return _com_call_wrapper(self._wrapped_object.__call__, *args, **kwargs)
def __repr__(self):
return 'ComWrapper<{}>'.format(repr(self._wrapped_object))
_xl = win32com.client.dynamic.Dispatch('Excel.Application')
xl = ComWrapper(_xl)
# Do stuff with xl instead of _xl, and calls will be attempted until the timeout is
# reached if "Call was rejected by callee."-exceptions are thrown.
Я дал тот же ответ на новый вопрос здесь: /questions/27112430/vyizov-byil-otklonen-vyizyivaemyim-polzovatelem-v-win32com-esli-otkryito-dialogovoe-okno-ili-excel-ozhidaet-drugogo-polzovatelya/49454224#49454224
Я запускаю интенсивные листы Excel, которые постоянно показывают эту (блокирующую) ошибку во время выполнения цикла расчета.
Решение состоит в том, чтобы использовать цикл for.
Я предоставляю раздел моего кода, который работает:
# it failed, keep trying
attempt_number = 0
reading_complete = False
while reading_complete==False:
try:
workbook = xw.Book(file_to_read)
reading_complete = True
print('file read...')
except:
reading_complete = False
attempt_number += 1
print('attempt:', attempt_number)
if attempt_number > 5:
print('no good: exiting the process')
exit()
Где:
- The
file_to_read
— это полный путь и имя книги Excel. - The
attempt_number
установлена переменная, ограничивающая количество попыток.
Стивен, возможно, мои имена переменных не хороши, но в коде нет грамматической ошибки, все работает нормально, меня беспокоит только ошибка com
мой скрипт выполняется без ошибок, если я не запустил другой Excel
Мой вопрос: кто-нибудь знает, как преодолеть это с помощью диспетчеризации ИЛИ есть ли другой модуль Excel для Python, где я могу решить эту проблему?
excel= Dispatch('Excel.Application')
excel.Visible = True
file_name = "E:\Report.xls"
workbook = excel.Workbooks.Open(file_name)
sheet=workbook.Sheets(1)
# consider i am writing somethin in excel
sheet.Cells(1,1).Value = 'test1'
sheet.Cells(1,2).Value = 'test2'
sheet.Cells(1,3).Value = 'test3'
sheet.Cells(1,4).Value = 'test4'
sheet.Cells(1,5).Value = 'test5'
sheet.Cells(1,6).Value = 'test6'
sheet.Cells(1,7).Value = 'test7'
sheet.Cells(1,8).Value = 'test8'