From 3fd858265813bc3475df27a60b2705649b131e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ppe?= Date: Fri, 6 Apr 2018 16:42:18 +0100 Subject: [PATCH] [dmlab_module_test, docs] Modify Python test to work in both Python 2.7 and Python 3. Also add an optional new dependency on the "six" package that is now used by this test. The remainder of DMLab is still usable without this package. Update documentation to point out the experimental Py3 support. --- README.md | 5 +++-- docs/users/python_api.md | 6 ++++++ python/tests/dmlab_module_test.py | 35 +++++++++++++++---------------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 189e48161..728f64bca 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,9 @@ software libraries, which we ship in several different ways: use can use either hardware-accelerated rendering via EGL or GLX or software rendering via OSMesa, depending on the `--define headless=...` build setting. - * Python 2.7 (other versions might work, too) with NumPy and PIL. (A few - tests require a NumPy version of at least 1.8.) + * Python 2.7 (other versions might work, too) with NumPy, PIL. (A few + tests require a NumPy version of at least 1.8.) One test requires six + to demonstrate Python 3 compatibility. The build rules are using a few compiler settings that are specific to GCC. If some flags are not recognized by your compiler (typically those would be diff --git a/docs/users/python_api.md b/docs/users/python_api.md index 14f0adcb3..f65c49c7f 100644 --- a/docs/users/python_api.md +++ b/docs/users/python_api.md @@ -8,6 +8,12 @@ usage, there is [python/random_agent.py](../../python/random_agent.py), and [python/random_agent_simple.py](../../python/random_agent_simple.py). +**A note about Python 3:** By and large the Python API requires Python 2.7. +However, there is experimental support for Python 3. Under Python 3, strings +coming out of the environment (e.g. event names or string observations) have to +be valid UTF-8. The `dmlab_module_test.py` demonstrates how to write code that +works both in Python 2.7 and Python 3 (using the `six` package). + ### class `deepmind_lab.Lab`(*level*, *observations*, *config={}*, *renderer='software'*) Creates an environment object, loading the game script file *level*. The diff --git a/python/tests/dmlab_module_test.py b/python/tests/dmlab_module_test.py index 7fcbba3c8..835cd545a 100644 --- a/python/tests/dmlab_module_test.py +++ b/python/tests/dmlab_module_test.py @@ -22,6 +22,7 @@ import os import unittest import numpy as np +import six import deepmind_lab @@ -31,7 +32,7 @@ class DeepMindLabTest(unittest.TestCase): def testInitArgs(self): with self.assertRaisesRegexp(TypeError, 'must be dict, not list'): deepmind_lab.Lab('tests/empty_room_test', [], ['wrongconfig']) - with self.assertRaisesRegexp(TypeError, 'str'): + with self.assertRaisesRegexp(TypeError, 'str|bad argument type'): deepmind_lab.Lab('tests/empty_room_test', [], {'wrongtype': 3}) with self.assertRaisesRegexp(TypeError, 'must be list, not None'): deepmind_lab.Lab('tests/empty_room_test', None, {}) @@ -83,7 +84,7 @@ def testRun(self, steps=10, observation='RGB_INTERLACED'): env = deepmind_lab.Lab('lt_chasm', [observation]) env.reset() - for _ in xrange(steps): + for _ in six.moves.range(steps): obs = env.observations() action = np.zeros((7,), dtype=np.intc) reward = env.step(action, num_steps=4) @@ -107,26 +108,25 @@ def testRunfilesPath(self): self.assertTrue(os.stat(deepmind_lab.runfiles_path())) def testWidthHeight(self, width=80, height=80, steps=10, num_steps=1): - observations = ['RGBD'] - env = deepmind_lab.Lab('lt_chasm', observations, - config={'height': str(height), - 'width': str(width)}) + observation = 'RGBD' + env = deepmind_lab.Lab( + 'lt_chasm', [observation], + config={'height': str(height), 'width': str(width)}) env.reset() - for _ in xrange(steps): + for _ in six.moves.range(steps): obs = env.observations() action = np.zeros((7,), dtype=np.intc) reward = env.step(action, num_steps=num_steps) - self.assertEqual(obs[observations[0]].shape, (4, width, height)) + self.assertEqual(obs[observation].shape, (4, width, height)) self.assertEqual(reward, 0.0) def testStringObervations(self): observation = 'CUSTOM_TEXT' env = deepmind_lab.Lab( 'tests/text_observation_test', [observation], - config={'height': str(32), - 'width': str(32)}) + config={'height': '32', 'width': '32'}) observation_spec = env.observation_spec() observation_spec_lookup = {o['name']: o for o in observation_spec} spec = observation_spec_lookup[observation] @@ -138,8 +138,8 @@ def testStringObervations(self): def testEvents(self): env = deepmind_lab.Lab( - 'tests/event_test', [], config={'height': str(32), - 'width': str(32)}) + 'tests/event_test', [], + config={'height': '32', 'width': '32'}) env.reset(episode=1, seed=7) events = env.events() self.assertEqual(len(events), 4) @@ -191,17 +191,16 @@ def testVeloctyObservations(self, width=80, height=80): backward_action = - forward_action look_sideways_action = np.array([512, 0, 0, 0, 0, 0, 0], dtype=np.intc) - env = deepmind_lab.Lab('seekavoid_arena_01', ['VEL.TRANS', 'VEL.ROT'], - config={'height': str(height), - 'width': str(width), - 'fps': '60'}) + env = deepmind_lab.Lab( + 'seekavoid_arena_01', ['VEL.TRANS', 'VEL.ROT'], + config={'height': str(height), 'width': str(width), 'fps': '60'}) env.reset(seed=1) # Initial landing on the ground. env.step(noop_action, num_steps=180) - for _ in xrange(3): + for _ in six.moves.range(3): # Doing nothing should result in velocity observations of zero. env.step(noop_action, num_steps=100) obs = env.observations() @@ -227,7 +226,7 @@ def testVeloctyObservations(self, width=80, height=80): env.reset(seed=1) - for _ in xrange(3): + for _ in six.moves.range(3): env.step(noop_action, num_steps=100) obs = env.observations() np.testing.assert_array_equal(obs['VEL.TRANS'], np.zeros((3,)))