2017-05-12 1 views
0

私は最後にhttps://github.com/tyarkoni/transitions/issues/198のタイムアウトメカニズムを実装しようとしています。私は状態の入力時に(タイムアウト状態のコンストラクタのパラメータとして)デフォルトのタイムアウトを設定し、終了時にそれをキャンセルすることを目指します。階層型ステートマシンの定義済みタイムアウトの設定と取り消しに失敗しました(012:参照:https://github.com/tyarkoni/transitions/issues/198)

Traceback (most recent call last): 
File "/usr/local/lib/python2.7/dist-packages/IPython/core/interactiveshell.py", line 2481, in safe_execfile 
self.compile if kw['shell_futures'] else None) 
File "/usr/local/lib/python2.7/dist-packages/IPython/utils/py3compat.py", line 289, in execfile 
builtin_mod.execfile(filename, *where) 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/hierasms.py", line 143, in <module> 
collector.model.collect(a='acall1') # collecting 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/plugged/transitions/core.py", line 248, in trigger 
return self.machine._process(f) 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/plugged/transitions/core.py", line 590, in _process 
return trigger() 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/plugged/transitions/extensions/nesting.py", line 131, in _trigger 
if t.execute(event): 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/plugged/transitions/extensions/nesting.py", line 100, in execute 
return super(NestedTransition, self).execute(event_data) 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/plugged/transitions/core.py", line 174, in execute 
self._change_state(event_data) 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/plugged/transitions/extensions/nesting.py", line 108, in _change_state 
lvl = source_state.exit_nested(event_data, dest_state) 
File "/home/sge/workspace_neon/VS_AREA51/ocpp16j_experimental/plugged/transitions/extensions/nesting.py", line 81, in exit_nested 
tmp_self.exit(event_data) 
TypeError: exit() takes exactly 1 argument (2 given) 

と、ここでのコード(Pythonの2.7.6/IPython 5.1.0/0.4.2トランジション):

from threading import Thread, Event 
from transitions.extensions import HierarchicalMachine as Machine 
from transitions.extensions.nesting import NestedState as State 
# Set up logging 
import logging 
from transitions import logger 
logger.setLevel(logging.DEBUG) 


class Timeout(Thread): 

    def __init__(self, func, timeout, **kwargs): 
#   self.lgtout=logging.getLogger(".".join([__name__, self.__class__.__name__])) 
     super(Timeout, self).__init__() 
     self.func = func 
     self.kwargs = kwargs 
     self.cancelEvt=Event() 
     self.cancelEvt.clear() #make ready for delay 
     self.timeout = timeout 
     print '---->Starting countdown from: '+str(self.timeout) 
     self.start() 


    def run(self): 
     self.cancelEvt.wait(self.timeout) 
     if not self.cancelEvt.isSet(): 
      print '---->Timeout of ' +str(self.timeout)+ ' occurred in thread'+str(self.ident) 
      self.func(**self.kwargs) # trigger the sm 
     else: 
      print '---->Timeout of ' +str(self.timeout)+ ' canceled in thread'+str(self.ident) 


class TimeoutState(State): 

    def __init__(self, name, timeout=3, timeoutSmTrigger='timeOUT', *args, **kwargs): 
     self.timeout = timeout 
     self._timer=None 
     self.timeoutSmTrigger=timeoutSmTrigger 
     super(TimeoutState, self).__init__(name=name, *args, **kwargs) 
     print 'timeout state created: ',name 


    def enter(self, **kwargs): 
     # initialise timeout 
     print 'enter: '+str(kwargs) 
     timeout = kwargs.pop('timeout',self.timeout) 
     timeoutSmTrigger = kwargs.pop('timeoutSmTrigger',self.timeoutSmTrigger) 
     func = getattr(kwargs.get('model',None), timeoutSmTrigger) 
     self._timer = Timeout(func, timeout, **kwargs) 


    def exit(self, **kwargs): 
     print 'enter: '+str(kwargs) 
     if self._timer: 
      self._timer.cancelEvt.set() 


class TimeoutMachine(Machine): 

    def __init__(self, name, states, transitions, initial, model=None): 
     super(TimeoutMachine,self).__init__(model=model, states=states, initial=initial, transitions=transitions, 
            send_event=False, 
            auto_transitions=False, ordered_transitions=False, 
            ignore_invalid_triggers=False, name=name, queued=False) 



    def _create_state(self, *args, **kwargs): 
     ''' 
     Overwrite to create all the way states with timeout mechanism 
     ''' 
     return TimeoutState(*args, **kwargs)  


class CntModel(object): 

    def bcall(self,**kwargs): 
     print 'before increase: ',str(kwargs) 
#   logger.debug('---------bcall done') 

    ''' 
    timeout indicator 
    '''  
    def timeOUT(self, **kwargs): 
     print 'Time out occurred' 



count_states = [{'name':'1','timeout':'4','timeoutSmTrigger':'timeOUT'}, '2', '3', 'done'] 
# count_states = [{'name':'1'}, '2', '3', 'done'] 

count_trans = [ 
    {'trigger':'increase', 'source':'1','dest':'2', 'before':'bcall'}, 
    ['increase', '2', '3'], 
    ['decrease', '3', '2'], 
    ['decrease', '2', '1'], 
    ['done', '3', 'done'], 
    ['reset', '*', '1'] 
] 


counter = TimeoutMachine(name='Counter',states=count_states, transitions=count_trans, initial='1') 

class ColModel(CntModel): 
    def acall(self, **kwargs): 
     print 'acall ',str(kwargs) 
#   logger.debug('-------acall done') 



states = ['waiting', 'collecting', {'name': 'counting', 'children': counter}] 
transitions = [ 
    {'trigger':'collect', 'source':'*','dest':'collecting', 'after':'acall'}, 
    ['wait', '*', 'waiting'], 
    ['count', 'collecting', 'counting_1'] 
] 

colm = ColModel() #composed model 

collector = TimeoutMachine(name='Collector', model=[colm], states=states, transitions=transitions, initial='waiting') 

collector.model.collect(a='acall1') # collecting 
collector.model.count() # let's see what we got 
collector.model.increase(a='inc1') # counting_2 
collector.model.increase(a='inc2') # counting_3 
collector.model.done() # collector.state == counting_done 
collector.model.wait() # collector.state == waiting 

logger.handlers=[] 

おかげ状態を終了しているときにエラーがoccures!

+0

私は、提供されたコードサンプルを可能な限り煮詰めるのが良い方法と考えています。これにより、他の開発者があなたを助けてくれる可能性が高くなります。また、一般的で成功したデバッグ手順もあります。私は、多くの開発者がよく述べたStackoverflowの質問を作成しながら、彼らの問題の解決策を見つけたことは確かです。 – aleneum

答えて

1

TimeoutState.enter/exitの定義には、位置引数(*args)がありません。マシンは、の状態でself.enter(event_data)を位置引数として呼び出します。 ** kwargsは引数のみをキーワード(例:key=value)にマッピングするため、これはdef(self, **kwargs)に適合しません。

前に状態が入力されていないので、TimeoutState.exitにエラーが発生します。 Machine.initial多かれ少なかれ、、beforeまたはenterを呼び出さずに、合格した状態のモデルのスポーンが出ます。

あなたは*args**kwargsが付属して柔軟性を必要としない限り、私は(言及githubの問題のように)継承したクラスのメソッドの定義を使用することをお勧めします:

class TimeoutState(State): 

    def __init__(self, name, timeout=3, timeoutSmTrigger='timeOUT', *args, **kwargs): 
     super(TimeoutState, self).__init__(name=name, *args, **kwargs) 

    def enter(self, event_data): 
     super(TimeoutState, self).enter(event_data) 

    def exit(self, event_data): 
     super(TimeoutState, self).exit(event_data) 

あなたが探している引数はプロパティですevent_data。 トリガーに引数を渡すと(e.g. collector.model.count)、位置引数はevent_data.args、キーワード引数はevent_data.kwargsになります。さらにevent_data.modelからモデルを取得します。

**kwargsから状態プロパティを取得しようとしているように見えるので、パラメータを取得する場所を確認することをお勧めします。これは、作業コードにつながる可能性がありますが、より多くの問題があるようです。たとえば、getattr(kwargs.get('model', None), timeoutSmTrigger)にgetattrとgetattrを連鎖させる方法は、kwargsにモデルが含まれていないと、デフォルトのNoneAttributeErrorになるため、あまり役に立ちません。

+0

ありがとうアレックス! – steval

関連する問題