Я не могу сказать со стопроцентной уверенностью, но я предполагаю, что ваш BaseModel
уже содержит атрибуты и методы, которые перекрываются с методами, которыми transitions
хочет динамически декорировать вашу модель.
transitions
сделает «проверенное» назначение, которое означает, что оно будет назначать триггеры и вспомогательные функции для модели только тогда, когда требуемое имя еще не занято существующими атрибутами или методами. Причиной этого является то, что иногда люди не заботятся о триггерах и вызывают функции исключительно по имени (фактически, используя метод trigger
).
Я предполагаю, что ваш BaseModel
содержит присвоение атрибута, аналогичное [ 1], как показано ниже.
from transitions import Machine
import logging
class BaseModel:
def __init__(self, order_dict):
self.pay = None # [1] already defined attribute
def trigger(self): # [2] already defined method
pass
class OrderStateMachine(Machine):
order_states = ['pending', 'paid', 'shipped', 'delivered', 'canceled']
order_transitions = [
{'trigger': 'pay', 'source': 'pending', 'dest': 'paid'},
{'trigger': 'deliver', 'source': 'shipped', 'dest': 'delivered'},
{'trigger': 'cancel', 'source': 'shipped', 'dest': 'canceled'},
]
def __init__(self, order):
super().__init__(
model=order,
states=OrderStateMachine.order_states,
transitions=OrderStateMachine.order_transitions,
initial='pending'
)
class Order(BaseModel):
def __init__(self, order_dict):
super().__init__(order_dict)
self.machine = OrderStateMachine(self)
logging.basicConfig(level=logging.DEBUG)
# [2] will cause 'Model already contains an attribute 'trigger'. Skip binding.'
new_order = Order({})
new_order.state # returns 'pending'
# [1] will cause a TypeError: 'NoneType' object is not callable
new_order.pay()
new_order.state
Чтобы справиться с этим, необходимо убедиться, что имена триггеров и атрибуты модели являются взаимоисключающими, чтобы предотвратить конфликты имен. Если вы действительно определили все эти методы специально - например, для добавления некоторых подсказок завершения кода в вашу IDE - и вы ДЕЙСТВИТЕЛЬНО хотите сохранить их таким образом, вы можете переопределить метод Machine._checked_assignment
:
class OveriddingMachine(Machine):
# assign everything to the model ignoring already existing attributes
def _checked_assignment(self, model, name, func):
setattr(model, name, func)
Обратите внимание, что если вы сделаете это, ваша машина может связываться с вашей моделью нежелательным образом.