diff --git a/pade/behaviours/base.py b/pade/behaviours/base.py index df8788b..8256964 100644 --- a/pade/behaviours/base.py +++ b/pade/behaviours/base.py @@ -1,124 +1,82 @@ -''' -This file implements the needed Behaviour class extensions, in -order to PADE Scheduler be able to manage the agent behaviours. -''' +"""Framework for Intelligent Agents Development - PADE -from pade.behaviours.protocols import Behaviour -from pade.acl.messages import ACLMessage -from time import sleep -import queue +The MIT License (MIT) -class BaseBehaviour(Behaviour): +Copyright (c) 2019 Lucas S Melo - ''' BaseBehaviour class ihnerits from Behaviour class and - implements the basic methods for scheduled behaviours. - ''' - - def __init__(self, agent): - ''' This method initializes a new instance of BaseBehaviour - class and explicitly calls the Behaviour.__init__() method. - ''' - super().__init__(agent) - # Queue of received messages by the agent and unread by this behaviour - self.messages = queue.Queue() - # Lock object (to ensure the mutual exclusion, when needed) - self.__lock = None +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - def read(self, block = True): - ''' It gets the first message in the local message queue. - ''' - if block: - return self.messages.get() - else: - try: - return self.messages.get_nowait() - except queue.Empty: - return None - - - def send(self, message): - ''' This method gets a message and passes it to self.agent.send() method. - It was coded just to complement the pair read/send in the BaseBehaviour class. - The method self.agent.send() can still be used directly in the code. - ''' - self.agent.send(message) +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +Behaviours module +----------------- - def read_timeout(self, timeout): - ''' It tries to read a message twice until the end of timeout. - In cases of no messages, this method returns None - ''' - message = self.read(block = False) - if message != None: - return message - else: - sleep(timeout) - return self.read(block = False) +This module implements the base of the Behaviours classes, in order to enable +the PADE Scheduler to manage the agent behaviours. +@author: Italo Campos +""" - def receive(self, message): - ''' It sets a new message on local messages queue. - ''' - if isinstance(message, ACLMessage): - self.messages.put(message) - else: - raise ValueError('message object type must be ACLMessage!') +from pade.behaviours.protocols import Behaviour +from pade.acl.messages import ACLMessage +import queue, time +class BaseBehaviour(Behaviour): + ''' The basic behaviour class. + This class inherits from Behaviour class and implements the basic methods + for scheduled behaviours. + ''' def action(self): - ''' This is an abstract method that must be overridden in the - child classes, writing the main actions of this behaviour. + ''' An abstract method that performs the actions of the behaviour. + + This method must be overridden in the subclasses. ''' + pass def done(self): - ''' This is an abstract method that must be overridden in the - child classes, dealing with the finish of this behaviour. + ''' Defines when the behaviour ends. + + This method must be overridden in the subclasses. ''' + pass def wait(self, timeout): - ''' This method sleeps a behaviour until occurs a timeout. The - behaviour will execute normally afterwards. - ''' - sleep(timeout) - + ''' Sleeps a behaviour until occurs a timeout. - def on_end(self): - ''' The scheduler will calls this method after the self.done() - method returns True and before the end of this behaviour. It is - the last action of a behaviour. + Parameters + ---------- + timeout : float + The time to be waited. ''' - pass - - def has_messages(self): - ''' A method to returns if this behaviour has messages in its - received messages queue. - ''' - return self.messages.qsize() != 0 + time.sleep(timeout) - def add_lock(self, lock): - ''' Adds a threading.Lock object to this behaviour, allowing - it to execute the mutual exclusion correctly. - ''' - self.__lock = lock - + def on_end(self): + ''' Executes the final actions of the behaviou. - def lock(self): - ''' Tries to acquire the lock of the threading.Lock object. - The behaviour will block if fails. + The scheduler will call this method after the behaviour ends. May be + overriden in subclasses. ''' - self.__lock.acquire() - - def unlock(self): - ''' Releases the lock of the threading.Lock object, allowing - the other behaviours to acquire it. - ''' - self.__lock.release() \ No newline at end of file + pass \ No newline at end of file diff --git a/pade/behaviours/types.py b/pade/behaviours/types.py index 9e46110..a48d6e3 100644 --- a/pade/behaviours/types.py +++ b/pade/behaviours/types.py @@ -1,165 +1,361 @@ -''' -This file implements the BaseBehaviour class extensions. These classes -are used to model the agent behaviours. -''' +"""Framework for Intelligent Agents Development - PADE + +The MIT License (MIT) + +Copyright (c) 2019 Lucas S Melo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Behaviour types module +---------------------- + +This module implements the BaseBehaviour class extensions. These subclasses are +used to model the agent behaviours of various types. + +@author: Italo Campos +""" from pade.behaviours.base import BaseBehaviour from pade.acl.messages import ACLMessage +import queue, threading class SimpleBehaviour(BaseBehaviour): + ''' Class that implements the SimpleBehaviour. + + SimpleBehaviour class models a basic behaviour. The action() method must be + overridden in the subclasses to define the behaviour actions. The done() + method must indicate (by returning True) when this behaviour will finalize. - ''' SimpleBehaviour class models a basic behaviour. Its action() - and done() methods must be written in the subclasses. + Attributes + ---------- + _lock : threding.Lock() + The lock object used to implement mutual exclusion. ''' def __init__(self, agent): - ''' Simply calls the superclass __init__() method. ''' + Parameters + ---------- + agent : Agent + The agent which performs the behaviour. + ''' + super().__init__(agent) + self._lock = None + def action(self): - ''' This is an abstract method that must be overridden in the - subclasses, implementing the main actions of this behaviour. + ''' An abstract method that performs the actions of the behaviour. + + This method can be overridden in the subclasses. ''' + pass + def done(self): - ''' This is an abstract method that must be overridden in the - subclasses, dealing with the finish of this behaviour. + ''' Defines when the behaviour ends. + + This method must be overridden in the subclasses, defining exactly when + the behaviour will ends (by returning True). ''' + pass -class OneShotBehaviour(BaseBehaviour): + def block(self): + ''' Blocks the behaviour until a new message arrive. + ''' + + self.agent.message_event.wait() + + + def add_lock(self, lock): + ''' Adds a threading.Lock object to this behaviour. + + This allows the behaviour to execute the mutual exclusion. + + Parameters + ---------- + lock : threadong.Lock + The lock object. + ''' + + self._lock = lock + - ''' OneShotBehaviour class models a finite behaviour. It executes its - action() method only once. + @property + def lock(self): + ''' Returns the added lock object. + + Raises + ------ + AttributeError + If there is no a lock object added. + + Returns + ------- + threading.Lock + The local lock object. + ''' + + if self._lock != None: + return self._lock + else: + raise(AttributeError('No such lock object added to this behaviour.')) + + + +class CompoundBehaviour(BaseBehaviour): + ''' This class models compound behaviours in PADE. + + CompoundBehaviour is an abstract class to model behaviours that handle + other behaviours as sub-behaviours. This classe implements the general + add_subbehaviour(SimpleBehaviour) method that add simple behaviours in the + local queue as sub-behaviours. The actions of this class need to be + implemented in subclasses. + + Attributes + ---------- + _subbehaviours : list + The list of added subbehaviours. ''' def __init__(self, agent): + ''' + Parameters + ---------- + agent : Agent + The agent that holds the behaviour. + ''' + super().__init__(agent) + self.subbehaviours = list() + + + def add_subbehaviour(self, behaviour): + ''' Adds sub-behaviours in this sub-behaviour local list. + + Parameters + ---------- + behaviour : SimpleBehaviour + The simple behaviour to be added as sub-behaviour. + + Raises + ------ + ValueError + If the sub-behaviour not it a subclass from SimpleBehaviour. + ''' + + if isinstance(behaviour, SimpleBehaviour): + self.subbehaviours.append(behaviour) + else: + raise ValueError('sub-behaviours must be of the type SimpleBehaviour!') + + + +class OneShotBehaviour(SimpleBehaviour): + ''' This class models a finite behaviour. + + OneShotBehaviour are behaviours that executes its action() method only + once. + ''' def action(self): - ''' This is an abstract method that must be overridden in the - subclasses, implementing the main actions of this behaviour. + ''' An abstract method that performs the actions of the behaviour. + + This method can be overridden in the subclasses. ''' + pass + def done(self): - ''' This method ever returns True, indicating that the behaviour - will execute only once. It should not be changed in subclasses. + ''' Defines when the behaviour ends. + + This method always returns True and should not be overridden in the + subclasses. By returning True, the behaviour will execute only once. ''' + return True -class CyclicBehaviour(BaseBehaviour): - ''' CyclicBehaviour class models an infinite behaviour. It executes its - action() method until the end of the agent. - ''' +class CyclicBehaviour(SimpleBehaviour): + ''' This class models an infinite behaviour. - def __init__(self, agent): - super().__init__(agent) + CyclicBehaviour are behaviours that executes its action() method until the + end of the agent. + ''' def action(self): - ''' This is an abstract method that must be overridden in the - subclasses, implementing the main actions of this behaviour. + ''' An abstract method that performs the actions of the behaviour. + + This method can be overridden in the subclasses. ''' + pass + def done(self): - ''' This method ever returns False, indicating that the behaviour - will execute indefinitely. It should not be changed in subclasses. + ''' Defines when the behaviour ends. + + This method always returns False and should not be overridden in the + subclasses. By returning False, the behaviour will execute + indefinitely. ''' + return False -class WakeUpBehaviour(OneShotBehaviour): - ''' WakeUpBehaviour class models a finite behaviour. It executes its - actions only once, after a timeout occurs. The actions of this class - must be implemented into on_wake() method. A time value in seconds is - passed into its __init__() method. +class WakeUpBehaviour(OneShotBehaviour): + ''' This class models a finite behaviour that waits a timeout before + performs its actions. + + WakeUpBehaviour class models a finite behaviour that executes its actions + after a timeout. The actions of this class must be implemented into the + on_wake() method. + + Attributes + ---------- + time : float + The amount of time (in seconds) to be waited before the behaviour + performs its actions. ''' def __init__(self, agent, time): + ''' + Parameters + ---------- + agent : Agent + The agent that executes the behaviour. + time : float + The amount of time (in seconds) to be waited before the behaviour + performs its actions. + ''' + super().__init__(agent) self.time = time + def action(self): - ''' This is a method that executes the general functions of this - behaviour type. It should not be changed in subclasses. + ''' This method performs the actions of the behaviour. + + This method should not be overridden in the subclasses. Use the method + on_wake() to write the actions of this behaviour. ''' + self.wait(self.time) self.on_wake() + def on_wake(self): - ''' This is an abstract method that must be overridden in the - subclasses, implementing the main actions of this behaviour. + ''' An abstract method that performs the actions of the behaviour. + + This method can be overridden in the subclasses. ''' + pass -class TickerBehaviour(CyclicBehaviour): - ''' TickerBehaviour class models an infinite behaviour. It executes its - actions after a timeout occurs, while the agent lives. The actions of - this class must be implemented into on_tick() method. A time value in - seconds is passed into its __init__() method. +class TickerBehaviour(CyclicBehaviour): + ''' This class models an infinite behaviour that waits a timeout before + performs its actions. + + TickerBehaviour class models an infinite behaviour that always waits a + timeout before execute its actions. The actions of this class must be + implemented into the on_tick() method. + + Attributes + ---------- + time : float + The amount of time (in seconds) to be waited before each execution of + the behaviour. ''' def __init__(self, agent, time): + ''' + Parameters + ---------- + agent : Agent + The agent that executes the behaviour. + time : float + The amount of time (in seconds) to be waited before each execution + of the behaviour. + ''' + super().__init__(agent) self.time = time + def action(self): - ''' This is a method that executes the general functions of this - behaviour type. It should not be changed in subclasses. + ''' This method performs the actions of the behaviour. + + This method should not be overridden in the subclasses. Use the method + on_tick() to write the actions of this behaviour. ''' + self.wait(self.time) self.on_tick() + def on_tick(self): - ''' This is an abstract method that must be overridden in the - subclasses, implementing the main actions of this behaviour. + ''' An abstract method that performs the actions of the behaviour. + + This method can be overridden in the subclasses. ''' + pass -class SequentialBehaviour(OneShotBehaviour): - ''' SequentialBehaviour class models a compound behaviour. It executes - its sub-behaviours in a defined sequence. The execution order is defined - at the time that the sub-behavious are added. No overrides are required - in this class. - ''' +class SequentialBehaviour(CompoundBehaviour): + ''' This class models the sequential-compound behaviours in PADE. - def __init__(self, agent): - super().__init__(agent) - # Sub-behaviours list - self.subbehaviours = list() + SequentialBehaviour models a sequential-compound behaviour. This classe + adds SimpleBehaviour and its subclasses as sub-behaviours, and execute them + sequentially. The execution order is defined as the sub-behavious are + added. No overrides are required for this class. + ''' def action(self): - ''' This is a method that executes the general functions of this - behaviour type. It should not be changed in subclasses. + ''' This method performs the actions of the behaviour. + + This method executes sequentially the sub-behaviours. This method + should not be overridden in the subclasses. ''' + for behaviour in self.subbehaviours: behaviour.action() while not behaviour.done(): behaviour.action() behaviour.on_end() - def add_subbehaviour(self, behaviour): - ''' This method adds sub-behaviours in this behaviour - ''' - self.subbehaviours.append(behaviour) - def receive(self, message): - ''' Overridden method to pass a received message to sub-behaviours. + def done(self): + ''' Defines when the behaviour ends. + + This method always returns True and should not be overridden in the + subclasses. By returning True, the behaviour will execute only once. ''' - if isinstance(message, ACLMessage): - for behaviour in self.subbehaviours: - behaviour.messages.put(message) - else: - raise ValueError('message object type must be ACLMessage!') \ No newline at end of file + + return True \ No newline at end of file