diff --git a/Pipfile b/Pipfile index 5b4f7b47c..e97295d39 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [dev-packages] -pylint = "*" +pylint = "<2.0.0" [packages] "e1839a8" = {editable = true, path = "."} diff --git a/Pipfile.lock b/Pipfile.lock index 4b0f1bff9..9fa4fe231 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "e12ab6daed67802388ef47af7adbedda464918859565053f5eb55c0414824f3b" + "sha256": "3df51cef624b80961fd171b0c3e597f02a03cb2c76f04119e38bf80e90dbdbb6" }, "pipfile-spec": 6, "requires": { @@ -18,10 +18,10 @@ "default": { "adal": { "hashes": [ - "sha256:4c020807b3f3cfd90f59203077dd5e1f59671833f8c3c5028ec029ed5072f9ce", - "sha256:b48f37acf571ec74822ae3fe5db683e5cc9b0c2004aba9be6d582253740258c2" + "sha256:534ab04df7ab7c30bc7fe9526c3120e50b9496982f6c85001b05fd7cf4134eb7", + "sha256:a2a2f7e4a2d2e2014e3d5ff9f6d614af280c879a1dbf96bb64d92d85a814a645" ], - "version": "==1.0.2" + "version": "==1.1.0" }, "asn1crypto": { "hashes": [ @@ -32,10 +32,10 @@ }, "attrs": { "hashes": [ - "sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265", - "sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b" + "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", + "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb" ], - "version": "==18.1.0" + "version": "==18.2.0" }, "cachetools": { "hashes": [ @@ -46,10 +46,10 @@ }, "certifi": { "hashes": [ - "sha256:4c1d68a1408dd090d2f3a869aa94c3947cc1d967821d1ed303208c9f41f0f2f4", - "sha256:b6e8b28b2b7e771a41ecdd12d4d43262ecab52adebbafa42c77d6b57fb6ad3a4" + "sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638", + "sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a" ], - "version": "==2018.8.13" + "version": "==2018.8.24" }, "cffi": { "hashes": [ @@ -136,7 +136,7 @@ "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" ], - "markers": "python_version != '3.2.*' and python_version != '3.0.*' and python_version != '3.1.*' and python_version < '4' and python_version >= '2.6'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version < '4'", "version": "==4.5.1" }, "cryptography": { @@ -203,16 +203,6 @@ "editable": true, "path": "." }, - "enum34": { - "hashes": [ - "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", - "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", - "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", - "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" - ], - "markers": "python_version < '3.4'", - "version": "==1.1.6" - }, "eventlet": { "hashes": [ "sha256:c584163e006e613707e224552fafc63e4e0aa31d7de0ab18b481ac0b385254c8", @@ -274,11 +264,11 @@ }, "hypothesis": { "hashes": [ - "sha256:7ca43f68bbf0880600ca70d41c0f76fef65da0c02ad19241c15be74fb8988e83", - "sha256:c29d9d0bed9d21d9de407f4044e8632708d3a911c06738a2ce346a49858eb55d", - "sha256:c734f263a5f35f4bd2acadf0e9a36511d4500286eae04ba0a090d1be47c7d1ba" + "sha256:2b35192cd3562e478715fc604ba139587cf220c1337b94b27abcbaab64d050e7", + "sha256:6cfba53326f96b33af9836792eafcf706c86a255bcd47e7c551663fa63ac9b4c", + "sha256:cfd671c05dc650e5dce7f9827671e1427e0ec79efa2a132deb5eab99b8310349" ], - "version": "==3.69.1" + "version": "==3.70.3" }, "idna": { "hashes": [ @@ -287,14 +277,6 @@ ], "version": "==2.7" }, - "ipaddress": { - "hashes": [ - "sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794", - "sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c" - ], - "markers": "python_version < '3'", - "version": "==1.0.22" - }, "itsdangerous": { "hashes": [ "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" @@ -348,7 +330,7 @@ "sha256:cea2557ee6a9faa2c100947637ded68414e12b851633c4ce26e0311b2a2ed539", "sha256:d081707ef0081920533db30200a2d30d5c0ea9cf6afa7cf8881ae4516cc69c48" ], - "markers": "python_version != '3.0.*' and python_version != '3.1.*' and python_version >= '2.6' and python_version != '3.3.*' and python_version != '3.2.*'", + "markers": "python_version != '3.3.*' and python_version != '3.2.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version != '3.1.*'", "version": "==5.4.7" }, "pyasn1": { @@ -427,6 +409,7 @@ "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a" ], + "markers": "python_version != '3.3.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version < '4'", "version": "==2.19.1" }, "requests-oauthlib": { @@ -434,6 +417,7 @@ "sha256:8886bfec5ad7afb391ed5443b1f697c6f4ae98d0e5620839d8b4499c032ada3f", "sha256:e21232e2465808c0e892e0e4dbb8c2faafec16ac6dc067dd546e9b466f3deac8" ], + "markers": "python_version != '3.3.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version < '4'", "version": "==1.0.0" }, "rsa": { @@ -455,15 +439,15 @@ "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" ], - "markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.1.*' and python_version < '4' and python_version >= '2.6'", + "markers": "python_version != '3.3.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.6' and python_version != '3.0.*' and python_version < '4'", "version": "==1.23" }, "websocket-client": { "hashes": [ - "sha256:030bbfbf29ac9e315ffb207ed5ed42b6981b5038ea00d1e13b02b872cc95e8f6", - "sha256:a35bac3d9647c62c1ba3e8a7340385d92981f5486b033557d592138fd4b21b90" + "sha256:03763384c530b331ec3822d0b52ffdc28c3aeb8a900ac8c98b2ceea3128a7b4e", + "sha256:3c9924675eaf0b27ae22feeeab4741bb4149b94820bd3a143eeaf8b62f64d821" ], - "version": "==0.51.0" + "version": "==0.52.0" }, "werkzeug": { "hashes": [ @@ -479,49 +463,15 @@ "sha256:0ef2bf9f07c3150929b25e8e61b5198c27b0dca195e156f0e4d5bdd89185ca1a", "sha256:fc9b582dba0366e63540982c3944a9230cbc6f303641c51483fa547dcc22393a" ], - "markers": "python_version >= '2.6'", "version": "==1.6.5" }, - "backports.functools-lru-cache": { - "hashes": [ - "sha256:9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a", - "sha256:f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd" - ], - "markers": "python_version < '3.4'", - "version": "==1.5" - }, - "configparser": { - "hashes": [ - "sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a" - ], - "markers": "python_version == '2.7'", - "version": "==3.5.0" - }, - "enum34": { - "hashes": [ - "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", - "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", - "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", - "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" - ], - "markers": "python_version < '3.4'", - "version": "==1.1.6" - }, - "futures": { - "hashes": [ - "sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265", - "sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1" - ], - "markers": "python_version < '3' and python_version >= '2.6'", - "version": "==3.2.0" - }, "isort": { "hashes": [ "sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" ], - "markers": "python_version < '3' and python_version >= '2.6'", + "markers": "python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and python_version != '3.3.*' and python_version != '3.0.*'", "version": "==4.3.4" }, "lazy-object-proxy": { @@ -573,14 +523,6 @@ "index": "pypi", "version": "==1.9.3" }, - "singledispatch": { - "hashes": [ - "sha256:5b06af87df13818d14f08a028e42f566640aef80805c3b50c5056b086e3c2b9c", - "sha256:833b46966687b3de7f438c761ac475213e53b306740f1abfaa86e1d1aae56aa8" - ], - "markers": "python_version < '3.4'", - "version": "==3.4.0.3" - }, "six": { "hashes": [ "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", diff --git a/aimmo-game-worker/avatar_runner.py b/aimmo-game-worker/avatar_runner.py index 5cd0eca66..09bf84193 100644 --- a/aimmo-game-worker/avatar_runner.py +++ b/aimmo-game-worker/avatar_runner.py @@ -5,7 +5,8 @@ from six import StringIO -from simulation.action import WaitAction +from simulation.action import WaitAction, Action +from user_exceptions import InvalidActionException LOGGER = logging.getLogger(__name__) @@ -41,8 +42,7 @@ def process_avatar_turn(self, world_map, avatar_state, src_code): sys.stderr = output_log self._update_avatar(src_code) - action = self.avatar.handle_turn(world_map, avatar_state) - action = action.serialise() + action = self.decide_action(world_map, avatar_state) except Exception as e: traceback.print_exc() @@ -56,3 +56,9 @@ def process_avatar_turn(self, world_map, avatar_state, src_code): logs = output_log.getvalue() return {'action': action, 'log': logs, 'avatar_updated': avatar_updated} + + def decide_action(self, world_map, avatar_state): + action = self.avatar.handle_turn(world_map, avatar_state) + if not isinstance(action, Action): + raise InvalidActionException(action) + return action.serialise() diff --git a/aimmo-game-worker/setup.py b/aimmo-game-worker/setup.py index d066ca540..48973b269 100644 --- a/aimmo-game-worker/setup.py +++ b/aimmo-game-worker/setup.py @@ -13,6 +13,7 @@ ], tests_require=[ 'httmock', + 'mock' ], test_suite='tests', zip_safe=False, diff --git a/aimmo-game-worker/simulation/action.py b/aimmo-game-worker/simulation/action.py index 4e6264101..18651fc6f 100644 --- a/aimmo-game-worker/simulation/action.py +++ b/aimmo-game-worker/simulation/action.py @@ -1,7 +1,12 @@ -class Action(object): +from abc import ABCMeta, abstractmethod + +class Action: + __metaclass__ = ABCMeta + + @abstractmethod def serialise(self): - raise NotImplementedError + pass class WaitAction(Action): diff --git a/aimmo-game-worker/tests/test_avatar_runner.py b/aimmo-game-worker/tests/test_avatar_runner.py index 03bad66b1..a67dbb001 100644 --- a/aimmo-game-worker/tests/test_avatar_runner.py +++ b/aimmo-game-worker/tests/test_avatar_runner.py @@ -1,5 +1,9 @@ from unittest import TestCase + +import mock + from avatar_runner import AvatarRunner +from user_exceptions import InvalidActionException NORTH = {'x': 0, 'y': 1} SOUTH = {'x': 0, 'y': -1} @@ -100,3 +104,15 @@ def test_update_code_flag_with_syntax_errors(self): self.assertTrue(response['avatar_updated']) response = runner.process_avatar_turn(world_map={}, avatar_state={}, src_code=avatar) self.assertFalse(response['avatar_updated']) + + def test_invalid_action_exception(self): + avatar = '''class Avatar(object): + def handle_turn(self, world_map, avatar_state): + from simulation.action import MoveAction + from simulation.direction import NORTH + + ''' + runner = AvatarRunner() + runner._update_avatar(src_code=avatar) + with self.assertRaises(InvalidActionException): + runner.decide_action(world_map={}, avatar_state={}) diff --git a/aimmo-game-worker/user_exceptions.py b/aimmo-game-worker/user_exceptions.py new file mode 100644 index 000000000..810c60cb6 --- /dev/null +++ b/aimmo-game-worker/user_exceptions.py @@ -0,0 +1,4 @@ +class InvalidActionException(Exception): + def __init__(self, invalid_action_object): + message = '"{}" is not a valid action object.'.format(invalid_action_object) + super(InvalidActionException, self).__init__(message)