Ошибка при работе с 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'
Другие вопросы по тегам