Переопределить сеттер по свойству в win32com - PullRequest
0 голосов
/ 30 марта 2019

Я использую win32com для управления Visio из Python.

Получение и установка значений таблиц просты:

print(shp.CellsU('PinX').ResultStr(''))
# and
shp.CellsU('PinX').FormulaU = '1'

Пока все хорошо, но мне нужен более короткий синтаксиспереопределив сеттер и геттер, чтобы получить что-то вроде:

print(shp.PinX)
# and
shp.PinX = '1'

Итак, я выбрал свойство:

ShapeClass = type(shp)

def SetPinX(self,value):
    self.CellsU('PinX').FormulaU = value

def GetPinX(self):
    return self.CellsU('PinX').ResultStr('')

ShapeClass.PinX = property(GetPinX,SetPinX)

Теперь странный результат - Геттер работает просто отлично (print (shp.PinX) дает ожидаемое значение), но установщик не будет работать.

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~\AppData\Local\conda\conda\envs\YG_Package_1\lib\site-packages\win32com\client\__init__.py in __setattr__(self, attr, value)
    478                 try:
--> 479                         args, defArgs=self._prop_map_put_[attr]
    480                 except KeyError:

KeyError: 'PinX'

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
<ipython-input-28-23f68b65624d> in <module>()
----> 1 shp.PinX= '1'

~\AppData\Local\conda\conda\envs\YG_Package_1\lib\site-packages\win32com\client\__init__.py in __setattr__(self, attr, value)
    479                         args, defArgs=self._prop_map_put_[attr]
    480                 except KeyError:
--> 481                         raise AttributeError("'%s' object has no attribute '%s'" % (repr(self), attr))
    482                 self._oleobj_.Invoke(*(args + (value,) + defArgs))
    483         def _get_good_single_object_(self, obj, obUserName=None, resultCLSID=None):

AttributeError: '<win32com.gen_py.Microsoft Visio 15.0 Type Library.IVShape instance at 0x85710888>' object has no attribute 'PinX'

dir (ShapeClass) показывает атрибут PinX просто отлично.

Тестированиес собственным классом тоже работал.Так что ошибка не в том, как я реализую свойство.

Я подозреваю, что win32com испытывает проблемы с переопределением сеттеров.

У кого-нибудь есть идеи, как решить проблему

Ответы [ 2 ]

2 голосов
/ 03 апреля 2019

Базовый класс win32com.client.DispatchBaseClass использует __setattr__ для перехвата всех доступа к настройке атрибута.Это влияет на ваш объект собственности;установщики свойств вызываются только реализацией object.__setattr__ по умолчанию, а не пользовательским методом, используемым win32com.

Так что да, shp.PinX = '1' будет вызывать DispatchBaseClass.__setattr__('PinX', '1'), даже еслив классе определен дескриптор данных с именем PinX, который потерпит неудачу, поскольку он поддерживает только атрибуты, определенные интерфейсом COM.

Вам придется переопределить здесь метод __setattr__, чтобы проверитьдля доступных свойств в первую очередь.Вы можете создать подкласс DispatchBaseClass или определенные сгенерированные классы, или , мы могли бы просто сделать обезьянку-заплатку win32com напрямую:

import inspect
from win32com.client import DispatchBaseClass

dispatch_setattr = DispatchBaseClass.__setattr__

def allow_datadescriptor_setattr(self, name, value):
    # for non-private names, check if the attribute exists on the class
    # and is a data descriptor. If so, use object.__setattr__ to permit
    # the data descriptor to intercept attribute setting
    if name[:1] != '_' and inspect.isdatadescriptor(getattr(type(self), name, None)):
        return object.__setattr__(self, name, value)
    # private name, or doesn't exist on the class, or not a data descriptor
    # invoke the original win32com dispatch __setattr__
    dispatch_setattr(self, name, value)

DispatchBaseClass.__setattr__ = allow_datadescriptor_setattr

Выше можно разрешить любой дескриптор с __set__ или __delete__ метод для перехвата присваиваний их именам, а не только property объектам.

0 голосов
/ 01 апреля 2019

Вы смешиваете методы .Formula и .ResultStr. Ячейка может иметь:

.Formula .FormulaU .Результат .ResultU .ResultStr .ResultStrU
.FormulaForce .FormulaForceU

В вашем коде вы используете .ResultStr для получения содержимого ячейки и .FormulaU для установки ячейки. Я предлагаю вам взглянуть на API Visio, чтобы увидеть разницу между всеми этими. Если ячейка имеет защищенную формулу / значение, вам необходимо использовать методы .FormulaForce.

...