Skip to content
Permalink
Browse files

Merge branch 'release/3.1.3'

  • Loading branch information...
javipalanca committed Jul 18, 2019
2 parents dc1dd70 + ee656b7 commit a23ba50eb21d241d1a4c4c55cd9db24c00a74318
Showing with 66 additions and 10 deletions.
  1. +7 −0 HISTORY.rst
  2. +2 −0 README.rst
  3. +1 −1 setup.cfg
  4. +1 −1 setup.py
  5. +1 −1 spade/__init__.py
  6. +10 −2 spade/behaviour.py
  7. +16 −2 spade/container.py
  8. +2 −2 spade/web.py
  9. +26 −1 tests/test_container.py
@@ -2,6 +2,13 @@
History
=======

3.1.3 (2019-07-18)
------------------

* Added BDI plugin (https://github.com/javipalanca/spade_bdi).
* Improved the platform stop (quit_spade).
* Minor bug fixing.

3.1.2 (2019-05-14)
------------------

@@ -51,6 +51,8 @@ Features
Plugins
-------

- **spade_bdi** (BDI agents with AgentSpeak):
- Code: https://github.com/javipalanca/spade_bdi
- **spade_bokeh** (bokeh plots for agents):
- Code: https://github.com/javipalanca/spade_bokeh
- Documentation: https://spade-bokeh.readthedocs.io/
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 3.1.2
current_version = 3.1.3
commit = True
tag = False

@@ -27,7 +27,7 @@ def parse_requirements(filename):

setup(
name='spade',
version='3.1.2',
version='3.1.3',
description="Smart Python Agent Development Environment",
long_description=readme + '\n\n' + history,
author="Javi Palanca",
@@ -8,6 +8,6 @@

__author__ = """Javi Palanca"""
__email__ = 'jpalanca@gmail.com'
__version__ = '3.1.2'
__version__ = '3.1.3'

__all__ = ["agent", "behaviour", "message", "template"]
@@ -1,6 +1,8 @@
import collections
import logging
import traceback
from abc import ABCMeta, abstractmethod
from asyncio import CancelledError
from threading import Event
from datetime import timedelta, datetime
import time
@@ -252,15 +254,21 @@ def join(self, timeout=None):
checks whether behaviour is done or killed,
ortherwise it calls run() coroutine.
"""
cancelled = False
while not self._done() and not self.is_killed():
try:
await self._run()
await asyncio.sleep(0) # relinquish cpu
except CancelledError:
logger.info("Behaviour {} cancelled".format(self))
cancelled = True
except Exception as e:
logger.error("Exception running behaviour {}: {}".format(self, e))
logger.error("Exception running behaviour {behav}: {exc}".format(behav=self, exc=e))
logger.error(traceback.format_exc())
self.kill(exit_code=e)
try:
await self.on_end()
if not cancelled:
await self.on_end()
except Exception as e:
logger.error("Exception running on_end in behaviour {}: {}".format(self, e))
self.kill(exit_code=e)
@@ -1,5 +1,7 @@
import asyncio
import logging
import sys
from contextlib import suppress
from threading import Thread

from singletonify import singleton
@@ -122,17 +124,29 @@ def stop(self):
class AioThread(Thread):
def __init__(self, *args, **kwargs):
self.loop = asyncio.new_event_loop()
self.running = True
super().__init__(*args, **kwargs)

def run(self):
try:
self.loop.run_forever()
if sys.version_info >= (3, 7):
tasks = asyncio.all_tasks(loop=self.loop)
else:
tasks = asyncio.Task.all_tasks(loop=self.loop) # pragma: no cover
for task in tasks:
task.cancel()
with suppress(asyncio.CancelledError):
self.loop.run_until_complete(task)
self.loop.close()
logger.debug("Loop closed")
except Exception as e: # pragma: no cover
logger.error("Exception in the event loop: {}".format(e))

def finalize(self):
self.loop.call_soon_threadsafe(self.loop.stop)
logger.debug("Loop closed")
if self.running:
self.loop.call_soon_threadsafe(self.loop.stop)
self.running = False


def stop_container():
@@ -176,8 +176,8 @@ def timeago(date):

async def stop_now(self, request):
logger.warning("Stopping agent from web interface.")
self.agent.stop()
return aioweb.json_response({})
await self.agent.stop()
return aioweb.json_response({}) # pragma: no cover

@aiohttp_jinja2.template("internal_tpl_messages.html")
async def get_messages(self, request):
@@ -1,8 +1,10 @@
import asyncio

import aioxmpp
import pytest
from asynctest import MagicMock, CoroutineMock

from spade.behaviour import OneShotBehaviour
from spade.behaviour import OneShotBehaviour, CyclicBehaviour
from spade.container import Container
from spade.message import Message
from tests.utils import make_connected_agent
@@ -113,3 +115,26 @@ def test_unregister():

assert not container.has_agent(str(agent.jid))
assert container.has_agent(str(agent2.jid))


def test_cancel_tasks():
agent = make_connected_agent()

class Behav(CyclicBehaviour):
async def run(self):
await asyncio.sleep(100)
self.has_finished = True

behav = Behav()
behav.has_finished = False
agent.add_behaviour(behaviour=behav)
future = agent.start()
future.result()

assert not behav.has_finished

container = Container()
container.stop()

assert not behav.has_finished

0 comments on commit a23ba50

Please sign in to comment.
You can’t perform that action at this time.