Ошибка при работе с Excel с использованием Python - PullRequest
5 голосов
/ 15 сентября 2010

пока мой скрипт обновляется в одно 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 без ошибки ..

Ответы [ 4 ]

5 голосов
/ 23 марта 2011

Эта ошибка возникает из-за того, что вызываемый вами COM-объект отклонит внешний вызов, если он уже обрабатывает другую операцию. Там нет асинхронной обработки вызовов, и поведение может показаться случайным.

В зависимости от операции вы увидите либо pythoncom.com_error, либо pywintypes.com_error. Простой (если не элегантный) способ обойти эту проблему - заключить ваши вызовы в COM-объект с помощью try-exc и, если вы получили одну из этих ошибок доступа, повторите ваш вызов.

Для получения дополнительной информации см. Раздел «Обработка ошибок» в главе 12, отрывок из Программирование Python на Win32 . Автор - Mark Hammond & Andy Robinson (O'Reilly 2000).

Также есть некоторая полезная информация, в частности об Excel, в Сообщение в блоге Сью Кам Онна "Программирование на Python с помощью Excel, как преодолеть COM_error из файла python, созданного makepy" .

2 голосов
/ 21 июля 2017

Я недавно столкнулся с этой проблемой. Хотя может показаться, что может быть несколько основных причин, моя ситуация возникала из-за того, что Python выполнял последующие вызовы слишком быстро, чтобы Excel не отставал, особенно при обновлении внешних запросов. Я исправил эту прерывистую ошибку «Вызов был отклонен вызываемым абонентом», вставив time.sleep() между большинством моих вызовов и увеличив аргумент sleep для любых вызовов, которые являются особенно продолжительными (обычно между 7-15 секундами). Это позволяет Excel завершить выполнение каждой команды до того, как Python выпустит дополнительные команды.

0 голосов
/ 01 мая 2019

Я боролся с той же проблемой, но теперь я нашел решение, которое до сих пор работает для меня.

Я создал класс ComWrapper, в который оборачиваю объект Excel COM. Он автоматическиоборачивает каждый вложенный объект и вызов в 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.

Я дал тот же ответ на новый вопрос здесь: https://stackoverflow.com/a/55892457/2828033

0 голосов
/ 16 сентября 2010

Стивен, возможно, мои имена переменных не очень хороши, но в коде нет грамматической ошибки, все работает нормально. Меня беспокоит только то, что ошибка 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'
...