import win32com.client
from pywintypes import com_error
from time import sleep
#Настройки задержек
_DELAY = 0.1 # секунд
_TIMEOUT = 20.0 # секунд
#Создаем служебную функцию
def _com_call_wrapper(f, *args, **kwargs):
"""
Повторяет вызов при получении ошибки 'Call was rejected by callee/Вызов был отклонён.'
Повторение выполняется с задержкой n*_DELAY секунд где n - количество ошибок при обращении к COM. Повторение до тех пор, пока задержка не станет равной _TIMEOUT
"""
# Обрабатываем аргументы
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
n = 1
while True:
try:
result = f(*args, **kwargs)
except com_error as e:
if e.hresult == -2147418111:
if start_time is None:
start_time = time.time()
elif time.time() - start_time >= _TIMEOUT:
raise
time.sleep(_DELAY*n)
n += 1
continue
raise
break
if isinstance(result, win32com.client.CDispatch) or callable(result):
return ComWrapper(result)
return result
class ComWrapper(object):
"""
Объект-обёртка, который позволяет перехватывать вызовы к исходному объекту и оборачивать их в служебную функцию _com_call_wrapper
"""
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))
# Подключение к AutoCAD осуществляем через объект ComWrapper
acad = ComWrapper(win32com.client.dynamic.Dispatch("AutoCAD.Application"))