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,)))