11
votes

Erreur lors du travail avec Excel à l'aide de Python

Bien que mon script met à jour un excellent le même temps si je vais faire tout autre travail manuellement avec une autre erreur Excel surprend que j'utilise Dispatch xxx

Je reçois une erreur comme ça (, COM_ERROR (-2147418111, 'appel a été rejeté par Callee.', Aucun, aucun)

est qu'il y a un moyen de la surmonter ..Can i Mettre à jour une autre Excel sans obtenir d'erreur.


1 commentaires

Inclure l'intégralité de la trace afin que nous puissions voir quelle ligne a provoqué l'erreur. Quelques commentaires: premièrement, vous avez deux variables classeur et un classeur qui ne diffèrent que par une lettre majuscule. Probablement pas une bonne idée. Deuxièmement, il n'ya aucune raison de saisir le transport actif car vous en avez déjà une référence sur la ligne précédente (un classeur ouvert est immédiatement actif). Troisièmement, vous ne spécifiez pas de chemin pour votre nom de fichier, de sorte que votre code Python et votre feuille de calcul Excel se trouvent dans différents répertoires, OUVERT sera échoué. Enfin, peut-être feuilleté n'est pas hors de portée. Excel détient des feuilles dans un tableau à base de 1.


3 Réponses :


7
votes

Cette erreur se produit car l'objet COM que vous appelez rejetera un appel externe s'il manipule déjà une autre opération. Il n'y a pas de manipulation asynchrone des appels et le comportement peut sembler aléatoire.

Selon l'opération, vous verrez soit pythoncom.com_error ou pywintypes.com_error. Un moyen simple (si inélégant) de contourner ce problème consiste à envelopper vos appels dans l'objet COM avec essayer, sauf et, si vous obtenez une de ces erreurs d'accès, réessayez votre appel.

Pour certains fond Voir la section "Gestion des erreurs" du Chapitre 12 Extraits de Programmation Python sur Win32 par Mark Hammond & Andy Robinson (O'Reilly 2000).

Il y a aussi des informations utiles spécifiquement sur Excel dans SIEW KAM ONN'S Blog Post" Python Programmation avec Excel, comment surmonter COM_ERROR à partir du fichier Python généré de maquillage ".


1 commentaires

2ème lien est 404d



11
votes

J'ai récemment rencontré ce même problème. Bien que cela sonne comme il peut y avoir de multiples causes profondes, ma situation se produisait car Python effectuait des appels ultérieurs trop rapidement pour EXCEL pour suivre, en particulier avec des rafraîchissements externes de la requête. J'ai résolu cet "appel intermittent" a été rejeté par Callee "Erreur en insérant temps.sleep () entre la plupart de mes appels et en augmentant l'argument de sommeil pour tout appel particulièrement long (généralement entre 7-15 secondes ). Cela permet d'exceler le temps de terminer chaque commande avant que Python ait émis des commandes supplémentaires.


1 commentaires

C'est une réponse incroyablement utile. J'ai réconforé pendant deux jours pour une solution et cela fait la différence. Sense que la conduite d'une application d'interface graphique nécessite des retards.



2
votes

Je me débats avec le même problème, mais maintenant j'ai fait une solution qui fonctionne pour moi jusqu'à présent.

J'ai créé une classe, un comwrapper, que j'envoie l'objet Excel COM dans. Il enveloppe automatiquement tous les éléments imbriqués Objet et appelez-les dans le COMWrapper et les débouche lorsqu'ils sont utilisés comme arguments pour fonctionner des appels ou des assignations aux objets emballés. Le wrapper fonctionne en attrapant l'appel «appel a été rejeté par Callee» - Exceptions et réessayez l'appel jusqu'à ce que le délai d'attente défini au sommet est atteint. Si le délai d'attente est atteint, l'exception est finalement lancée à l'extérieur de l'objet wrapper. P>

Les appels de fonction sur des objets emballés sont automatiquement enveloppés par une fonction _com_call_wrapper, qui est l'endroit où la magie se produit. P>

Pour le faire fonctionner, enveloppez l'objet COM de l'expédition à l'aide du COMWrapper, puis utilisez-le comme d'habitude, comme au bas du code. Commentaire S'il y a des problèmes. P>

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.


0 commentaires