diff --git a/.gitignore b/.gitignore
index 15fb17b133b4c707651b8411b4934d2734968688..a003eda10b9827f972a29ecccbe9b67c3cfa7de1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -109,3 +109,4 @@ ENV/
 
 
 images/test/
+test_save.dat
diff --git a/MANIFEST.in b/MANIFEST.in
index 965b2dda7db7c49f68857dc3aea9af37e30a745e..30bf97cf0de32bad7e630a80e2b977eb85d48911 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,6 +3,7 @@ include CONTRIBUTING.rst
 include HISTORY.rst
 include LICENSE
 include README.rst
+include requirements_dev.txt
 
 recursive-include tests *
 recursive-exclude * __pycache__
diff --git a/examples/qt2.py b/examples/qt2.py
new file mode 100644
index 0000000000000000000000000000000000000000..6074106523c7fbe503f79b6bc7604f055dc27b35
--- /dev/null
+++ b/examples/qt2.py
@@ -0,0 +1,78 @@
+
+
+import sys
+from PyQt5 import QtSvg
+from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QGridLayout, QWidget
+from PyQt5.QtCore import Qt, QByteArray
+
+from flatland.utils import svg
+
+
+# Subclass QMainWindow to customise your application's main window
+class MainWindow(QMainWindow):
+
+    def __init__(self, *args, **kwargs):
+        super(MainWindow, self).__init__(*args, **kwargs)
+
+        self.setWindowTitle("My Awesome App")
+
+        layout = QGridLayout()
+        layout.setSpacing(0)
+
+        wMain = QWidget(self)
+
+        wMain.setLayout(layout)
+
+        label = QLabel("This is a PyQt5 window!")
+
+        # The `Qt` namespace has a lot of attributes to customise
+        # widgets. See: http://doc.qt.io/qt-5/qt.html
+        label.setAlignment(Qt.AlignCenter)
+        layout.addWidget(label, 0, 0)
+
+        svgWidget = QtSvg.QSvgWidget("./svg/Gleis_vertikal.svg")
+        layout.addWidget(svgWidget, 1, 0)
+
+        if True:
+            track = svg.Track()
+
+            svgWidget = None
+            iRow = 0
+            iCol = 2
+            iArt = 0
+            nCols = 3
+            for binTrans in list(track.dSvg.keys())[:2]:
+                sSVG = track.dSvg[binTrans].to_string()
+
+                bySVG = bytearray(sSVG, encoding='utf-8')
+
+                # with open(sfPath, "r") as fIn:
+                #    sSVG = fIn.read()
+                # bySVG = bytearray(sSVG, encoding='utf-8')
+
+                svgWidget = QtSvg.QSvgWidget()
+                oQB = QByteArray(bySVG)
+
+                bSuccess = svgWidget.renderer().load(oQB)
+                # print(x0, y0, x1, y1)
+                print(iRow, iCol, bSuccess)
+                print("\n\n\n", bySVG.decode("utf-8"))
+                # svgWidget.setGeometry(x0, y0, x1, y1)
+                layout.addWidget(svgWidget, iRow, iCol)
+
+                iArt += 1
+                iRow = int(iArt / nCols)
+                iCol = iArt % nCols
+
+        # Set the central widget of the Window. Widget will expand
+        # to take up all the space in the window by default.
+        self.setCentralWidget(wMain)
+
+
+app = QApplication(sys.argv)
+
+window = MainWindow()
+window.show()
+
+app.exec_()
+
diff --git a/examples/training_navigation.py b/examples/training_navigation.py
index 23970a9059f15ce89b59b1cbcb9b862d248d1cd5..cabb655e3eb2bc2d12d908559b0102b072163052 100644
--- a/examples/training_navigation.py
+++ b/examples/training_navigation.py
@@ -5,7 +5,7 @@ from flatland.utils.rendertools import *
 from flatland.baselines.dueling_double_dqn import Agent
 from collections import deque
 import torch, random
-
+import time
 random.seed(1)
 np.random.seed(1)
 
@@ -25,15 +25,16 @@ transition_probability = [15,  # empty cell - Case 0
 
 # Example generate a random rail
 """
-env = RailEnv(width=10,
-              height=10,
+env = RailEnv(width=20,
+              height=20,
               rail_generator=random_rail_generator(cell_type_relative_proportion=transition_probability),
               number_of_agents=1)
 """
 env = RailEnv(width=15,
               height=15,
-              rail_generator=complex_rail_generator(nr_start_goal=10, min_dist=5, max_dist=99999, seed=0),
+              rail_generator=complex_rail_generator(nr_start_goal=2, nr_extra=30, min_dist=5, max_dist=99999, seed=0),
               number_of_agents=3)
+
 """
 env = RailEnv(width=20,
               height=20,
@@ -117,10 +118,13 @@ for trials in range(1, n_trials + 1):
 
     # Reset environment
     obs = env.reset()
+
     final_obs = obs.copy()
     final_obs_next = obs.copy()
+
     for a in range(env.get_num_agents()):
         data, distance = env.obs_builder.split_tree(tree=np.array(obs[a]), num_features_per_node=5, current_depth=0)
+
         data = norm_obs_clip(data)
         distance = norm_obs_clip(distance)
         obs[a] = np.concatenate((data, distance))
@@ -136,7 +140,8 @@ for trials in range(1, n_trials + 1):
     # Run episode
     for step in range(100):
         if demo:
-            env_renderer.renderEnv(show=True)
+            env_renderer.renderEnv(show=True, obsrender=True)
+            time.sleep(2)
         # print(step)
         # Action
         for a in range(env.get_num_agents()):
@@ -149,7 +154,6 @@ for trials in range(1, n_trials + 1):
 
         # Environment step
         next_obs, all_rewards, done, _ = env.step(action_dict)
-
         for a in range(env.get_num_agents()):
             data, distance = env.obs_builder.split_tree(tree=np.array(next_obs[a]), num_features_per_node=5,
                                                         current_depth=0)
diff --git a/flatland/envs/agent_utils.py b/flatland/envs/agent_utils.py
index 1f1bc1db065057a5ced1c917c5a24e2decebf2fa..05f81e43be3f33bfdfc81911d6cf6272bfba2d7e 100644
--- a/flatland/envs/agent_utils.py
+++ b/flatland/envs/agent_utils.py
@@ -1,6 +1,7 @@
 
 from attr import attrs, attrib
 from itertools import starmap
+import numpy as np
 # from flatland.envs.rail_env import RailEnv
 
 
@@ -36,7 +37,18 @@ class EnvAgentStatic(object):
         return list(starmap(EnvAgentStatic, zip(positions, directions, targets)))
 
     def to_list(self):
-        return [self.position, self.direction, self.target]
+
+        # I can't find an expression which works on both tuples, lists and ndarrays
+        # which converts them all to a list of native python ints.
+        lPos = self.position
+        if type(lPos) is np.ndarray:
+            lPos = lPos.tolist()
+
+        lTarget = self.target
+        if type(lTarget) is np.ndarray:
+            lTarget = lTarget.tolist()
+
+        return [lPos, int(self.direction), lTarget]
 
 
 @attrs
diff --git a/flatland/envs/generators.py b/flatland/envs/generators.py
index 04e9a8fefac4ada79527f00200dc6fbfa3d7b924..c1578a816e2e30127fb77dda6e72ab51b2f41cb2 100644
--- a/flatland/envs/generators.py
+++ b/flatland/envs/generators.py
@@ -9,7 +9,7 @@ from flatland.envs.env_utils import distance_on_rail, connect_rail, get_directio
 from flatland.envs.env_utils import get_rnd_agents_pos_tgt_dir_on_rail
 
 
-def complex_rail_generator(nr_start_goal=1, nr_extra=10, min_dist=2, max_dist=99999, seed=0):
+def complex_rail_generator(nr_start_goal=1, nr_extra=100, min_dist=20, max_dist=99999, seed=0):
     """
     Parameters
     -------
diff --git a/flatland/envs/observations.py b/flatland/envs/observations.py
index 8e4be0ba49d8405aa420d2bc8e4854f6300e3837..651d83520ee1f492ea71ba6ddf82cfa5f9093964 100644
--- a/flatland/envs/observations.py
+++ b/flatland/envs/observations.py
@@ -205,7 +205,7 @@ class TreeObsForRailEnv(ObservationBuilder):
         # observation = [0, 0, 0, 0, self.distance_map[handle, position[0], position[1], orientation]]
         observation = [0, 0, 0, 0, self.distance_map[(handle, *agent.position, agent.direction)]]
         root_observation = observation[:]
-
+        visited = set()
         # Start from the current orientation, and see which transitions are available;
         # organize them as [left, forward, right, back], relative to the current orientation
         # If only one transition is possible, the tree is oriented with this transition as the forward branch.
@@ -219,8 +219,10 @@ class TreeObsForRailEnv(ObservationBuilder):
             if possible_transitions[branch_direction]:
                 new_cell = self._new_position(agent.position, branch_direction)
 
-                branch_observation = self._explore_branch(handle, new_cell, branch_direction, root_observation, 1)
+                branch_observation, branch_visited = \
+                    self._explore_branch(handle, new_cell, branch_direction, root_observation, 1)
                 observation = observation + branch_observation
+                visited = visited.union(branch_visited)
             else:
                 num_cells_to_fill_in = 0
                 pow4 = 1
@@ -228,6 +230,7 @@ class TreeObsForRailEnv(ObservationBuilder):
                     num_cells_to_fill_in += pow4
                     pow4 *= 4
                 observation = observation + [-np.inf, -np.inf, -np.inf, -np.inf, -np.inf] * num_cells_to_fill_in
+        self.env.dev_obs_dict[handle] = visited
         return observation
 
     def _explore_branch(self, handle, position, direction, root_observation, depth):
@@ -236,7 +239,7 @@ class TreeObsForRailEnv(ObservationBuilder):
         """
         # [Recursive branch opened]
         if depth >= self.max_depth + 1:
-            return []
+            return [], []
 
         # Continue along direction until next switch or
         # until no transitions are possible along the current direction (i.e., dead-ends)
@@ -377,22 +380,24 @@ class TreeObsForRailEnv(ObservationBuilder):
                 # Swap forward and back in case of dead-end, so that an agent can learn that going forward takes
                 # it back
                 new_cell = self._new_position(position, (branch_direction + 2) % 4)
-                branch_observation = self._explore_branch(handle,
-                                                          new_cell,
-                                                          (branch_direction + 2) % 4,
-                                                          new_root_observation,
-                                                          depth + 1)
+                branch_observation, branch_visited = self._explore_branch(handle,
+                                                                          new_cell,
+                                                                          (branch_direction + 2) % 4,
+                                                                          new_root_observation,
+                                                                          depth + 1)
                 observation = observation + branch_observation
-
+                if len(branch_visited) != 0:
+                    visited = visited.union(branch_visited)
             elif last_isSwitch and possible_transitions[branch_direction]:
                 new_cell = self._new_position(position, branch_direction)
-                branch_observation = self._explore_branch(handle,
-                                                          new_cell,
-                                                          branch_direction,
-                                                          new_root_observation,
-                                                          depth + 1)
+                branch_observation, branch_visited = self._explore_branch(handle,
+                                                                          new_cell,
+                                                                          branch_direction,
+                                                                          new_root_observation,
+                                                                          depth + 1)
                 observation = observation + branch_observation
-
+                if len(branch_visited) != 0:
+                    visited = visited.union(branch_visited)
             else:
                 num_cells_to_fill_in = 0
                 pow4 = 1
@@ -401,7 +406,7 @@ class TreeObsForRailEnv(ObservationBuilder):
                     pow4 *= 4
                 observation = observation + [-np.inf, -np.inf, -np.inf, -np.inf, -np.inf] * num_cells_to_fill_in
 
-        return observation
+        return observation, visited
 
     def util_print_obs_subtree(self, tree, num_features_per_node=5, prompt='', current_depth=0):
         """
diff --git a/flatland/envs/rail_env.py b/flatland/envs/rail_env.py
index a5248a8fb3b5a7ee2d433aa12c5daca84753e6e9..118ebf4d3ea122519a09c8b7b5a00c53964063a1 100644
--- a/flatland/envs/rail_env.py
+++ b/flatland/envs/rail_env.py
@@ -98,7 +98,7 @@ class RailEnv(Environment):
 
         self.obs_dict = {}
         self.rewards_dict = {}
-
+        self.dev_obs_dict = {}
         # self.agents_handles = list(range(self.number_of_agents))
 
         # self.agents_position = []
@@ -315,6 +315,7 @@ class RailEnv(Environment):
 
     def _get_observations(self):
         self.obs_dict = {}
+        self.debug_obs_dict = {}
         # for handle in self.agents_handles:
         for iAgent in range(self.get_num_agents()):
             self.obs_dict[iAgent] = self.obs_builder.get(iAgent)
@@ -328,6 +329,11 @@ class RailEnv(Environment):
         grid_data = self.rail.grid.tolist()
         agent_static_data = [agent.to_list() for agent in self.agents_static]
         agent_data = [agent.to_list() for agent in self.agents]
+
+        msgpack.packb(grid_data)
+        msgpack.packb(agent_data)
+        msgpack.packb(agent_static_data)
+
         msg_data = {
             "grid": grid_data,
             "agents_static": agent_static_data,
diff --git a/flatland/utils/rendertools.py b/flatland/utils/rendertools.py
index 4921def4218beef21e119a3979bbb88c02af984d..34f3e9fa6857e86f4d99d211784d983a2e2a1e75 100644
--- a/flatland/utils/rendertools.py
+++ b/flatland/utils/rendertools.py
@@ -10,6 +10,7 @@ from flatland.utils.render_qt import QTGL, QTSVG
 from flatland.utils.graphics_pil import PILGL
 from flatland.utils.graphics_layer import GraphicsLayer
 
+
 # TODO: suggested renaming to RailEnvRenderTool, as it will only work with RailEnv!
 
 
@@ -100,12 +101,11 @@ class RenderTool(object):
     lColors = list("brgcmyk")
     # \delta RC for NESW
     gTransRC = np.array([[-1, 0], [0, 1], [1, 0], [0, -1]])
-    nPixCell = 1   # misnomer...
+    nPixCell = 1  # misnomer...
     nPixHalf = nPixCell / 2
     xyHalf = array([nPixHalf, -nPixHalf])
     grc2xy = array([[0, -nPixCell], [nPixCell, 0]])
-    gGrid = array(np.meshgrid(np.arange(10), -np.arange(10))) * \
-        array([[[nPixCell]], [[nPixCell]]])
+    gGrid = array(np.meshgrid(np.arange(10), -np.arange(10))) * array([[[nPixCell]], [[nPixCell]]])
     # xyPixHalf = xr.DataArray([nPixHalf, -nPixHalf],
     #                         dims="xy",
     #                         coords={"xy": ["x", "y"]})
@@ -130,7 +130,7 @@ class RenderTool(object):
             self.gl = PILGL(env.width, env.height)
         elif gl == "QTSVG":
             self.gl = QTSVG(env.width, env.height)
-        
+
         self.new_rail = True
 
     def set_new_rail(self):
@@ -153,14 +153,14 @@ class RenderTool(object):
 
     def plotAgents(self, targets=True, iSelectedAgent=None):
         cmap = self.gl.get_cmap('hsv',
-            lut=max(len(self.env.agents), len(self.env.agents_static) + 1))
+                                lut=max(len(self.env.agents), len(self.env.agents_static) + 1))
 
         for iAgent, agent in enumerate(self.env.agents_static):
             if agent is None:
                 continue
             oColor = cmap(iAgent)
             self.plotAgent(agent.position, agent.direction, oColor, target=agent.target if targets else None,
-                static=True, selected=iAgent == iSelectedAgent)
+                           static=True, selected=iAgent == iSelectedAgent)
 
         for iAgent, agent in enumerate(self.env.agents):
             if agent is None:
@@ -211,8 +211,8 @@ class RenderTool(object):
         """
         rt = self.__class__
 
-        rcDir = rt.gTransRC[iDir]                    # agent direction in RC
-        xyDir = np.matmul(rcDir, rt.grc2xy)          # agent direction in xy
+        rcDir = rt.gTransRC[iDir]  # agent direction in RC
+        xyDir = np.matmul(rcDir, rt.grc2xy)  # agent direction in xy
 
         xyPos = np.matmul(rcPos - rcDir / 2, rt.grc2xy) + rt.xyHalf
 
@@ -220,7 +220,7 @@ class RenderTool(object):
             color = self.gl.adaptColor(color, lighten=True)
 
         # print("Agent:", rcPos, iDir, rcDir, xyDir, xyPos)
-        self.gl.scatter(*xyPos, color=color, marker="o", s=100)            # agent location
+        self.gl.scatter(*xyPos, color=color, marker="o", s=100)  # agent location
         xyDirLine = array([xyPos, xyPos + xyDir / 2]).T  # line for agent orient.
         self.gl.plot(*xyDirLine, color=color, lw=5, ms=0, alpha=0.6)
         if selected:
@@ -398,7 +398,7 @@ class RenderTool(object):
                 xyPrev = xy
 
     def drawTrans2(
-            self,
+        self,
             xyLine, xyCentre,
             rotation, bDeadEnd=False,
             sColor="gray",
@@ -420,9 +420,9 @@ class RenderTool(object):
 
             if sColor == "auto":
                 if dx > 0 or dy > 0:
-                    sColor = "C1"   # N or E
+                    sColor = "C1"  # N or E
                 else:
-                    sColor = "C2"   # S or W
+                    sColor = "C2"  # S or W
 
             if bDeadEnd:
                 xyLine2 = array([
@@ -472,12 +472,29 @@ class RenderTool(object):
                     xyMid + [-dx + dy, -dx - dy]])
                 self.gl.plot(*xyArrow.T, color=sColor)
 
+    def renderObs(self, agent_handles, observation_dict):
+        """
+        Render the extent of the observation of each agent. All cells that appear in the agent obsrevation will be
+        highlighted.
+        :param agent_handles: List of agent indices to adapt color and get correct observation
+        :param observation_dict: dictionary containing sets of cells of the agent observation
+
+        """
+        rt = self.__class__
+
+        cmap = self.gl.get_cmap('hsv', lut=max(len(self.env.agents), len(self.env.agents_static) + 1))
+
+        for agent in agent_handles:
+            color = cmap(agent)
+            for visited_cell in observation_dict[agent]:
+                cell_coord = array(visited_cell[:2])
+                cell_coord_trans = np.matmul(cell_coord, rt.grc2xy) + rt.xyHalf
+                self._draw_square(cell_coord_trans, 1 / 3, color)
+
     def renderEnv(
-            self, show=False, curves=True, spacing=False,
-            arrows=False, agents=True, sRailColor="gray",
-            frames=False, iEpisode=None, iStep=None,
-            iSelectedAgent=None,
-            action_dict=None):
+        self, show=False, curves=True, spacing=False,
+            arrows=False, agents=True, obsrender=True, sRailColor="gray", frames=False, iEpisode=None, iStep=None,
+            iSelectedAgent=None, action_dict=None):
         """
         Draw the environment using matplotlib.
         Draw into the figure if provided.
@@ -488,15 +505,16 @@ class RenderTool(object):
 
         if not self.gl.is_raster():
             self.renderEnv2(show, curves, spacing,
-            arrows, agents, sRailColor,
-            frames, iEpisode, iStep,
-            iSelectedAgent, action_dict)
+                            arrows, agents, sRailColor,
+                            frames, iEpisode, iStep,
+                            iSelectedAgent, action_dict)
             return
 
         # cell_size is a bit pointless with matplotlib - it does not relate to pixels,
         # so for now I've changed it to 1 (from 10)
         cell_size = 1
         self.gl.beginFrame()
+
         # self.gl.clf()
         # if oFigure is None:
         #    oFigure = self.gl.figure()
@@ -528,9 +546,9 @@ class RenderTool(object):
             for c in range(env.width):
 
                 # bounding box of the grid cell
-                x0 = cell_size * c       # left
-                x1 = cell_size * (c + 1)   # right
-                y0 = cell_size * -r      # top
+                x0 = cell_size * c  # left
+                x1 = cell_size * (c + 1)  # right
+                y0 = cell_size * -r  # top
                 y1 = cell_size * -(r + 1)  # bottom
 
                 # centres of cell edges
@@ -538,7 +556,7 @@ class RenderTool(object):
                     ((x0 + x1) / 2.0, y0),  # N middle top
                     (x1, (y0 + y1) / 2.0),  # E middle right
                     ((x0 + x1) / 2.0, y1),  # S middle bottom
-                    (x0, (y0 + y1) / 2.0)   # W middle left
+                    (x0, (y0 + y1) / 2.0)  # W middle left
                 ]
 
                 # cell centre
@@ -611,7 +629,8 @@ class RenderTool(object):
         # Draw each agent + its orientation + its target
         if agents:
             self.plotAgents(targets=True, iSelectedAgent=iSelectedAgent)
-
+        if obsrender:
+            self.renderObs(range(env.get_num_agents()), env.dev_obs_dict)
         # Draw some textual information like fps
         yText = [-0.3, -0.6, -0.9]
         if frames:
@@ -665,18 +684,18 @@ class RenderTool(object):
         gP0 = array([[0, 0, 0]]).T
         nDepth = 2
         for i in range(nDepth):
-            nDepthNodes = nBranchFactor**i
+            nDepthNodes = nBranchFactor ** i
             # rScale = nBranchFactor ** (nDepth - i)
-            rShrinkDepth = 1/(i+1)
+            rShrinkDepth = 1 / (i + 1)
             # gX1 = np.linspace(-nDepthNodes / 2, nDepthNodes / 2, nDepthNodes) * rShrinkDepth
-            
-            gX1 = np.linspace(-(nDepthNodes-1), (nDepthNodes-1), nDepthNodes) * rShrinkDepth
+
+            gX1 = np.linspace(-(nDepthNodes - 1), (nDepthNodes - 1), nDepthNodes) * rShrinkDepth
             gY1 = np.ones((nDepthNodes)) * i
             gZ1 = np.zeros((nDepthNodes))
-            
+
             gP1 = array([gX1, gY1, gZ1])
             gP01 = np.append(gP0, gP1, axis=1)
-            
+
             if nDepthNodes > 1:
                 nDepthNodesPrev = nDepthNodes / nBranchFactor
                 giP0 = np.repeat(np.arange(nDepthNodesPrev), nBranchFactor)
@@ -687,12 +706,10 @@ class RenderTool(object):
                 self.gl.plot(gP01[0], -gP01[1], lines=giLinePoints, color="gray")
 
             gP0 = array([gX1, gY1, gZ1])
-    
+
     def renderEnv2(
-            self, show=False, curves=True, spacing=False,
-            arrows=False, agents=True, sRailColor="gray",
-            frames=False, iEpisode=None, iStep=None,
-            iSelectedAgent=None,
+        self, show=False, curves=True, spacing=False, arrows=False, agents=True, renderobs=True, sRailColor="gray",
+            frames=False, iEpisode=None, iStep=None, iSelectedAgent=None,
             action_dict=dict()):
         """
         Draw the environment using matplotlib.
@@ -710,12 +727,11 @@ class RenderTool(object):
             # Draw each cell independently
             for r in range(env.height):
                 for c in range(env.width):
-
                     binTrans = env.rail.grid[r, c]
                     self.gl.setRailAt(r, c, binTrans)
 
         cmap = self.gl.get_cmap('hsv',
-            lut=max(len(self.env.agents), len(self.env.agents_static) + 1))
+                                lut=max(len(self.env.agents), len(self.env.agents_static) + 1))
 
         for iAgent, agent in enumerate(self.env.agents):
             if agent is None:
@@ -729,14 +745,14 @@ class RenderTool(object):
             if iAgent in action_dict:
                 iAction = action_dict[iAgent]
                 new_direction, action_isValid = self.env.check_action(agent, iAction)
-            
+
             if action_isValid:
                 self.gl.setAgentAt(iAgent, *agent.position, agent.direction, new_direction, color=oColor)
             else:
                 pass
                 # print("invalid action - agent ", iAgent, " bend ", agent.direction, new_direction)
                 # self.gl.setAgentAt(iAgent, *agent.position, agent.direction, new_direction)
-                
+
         self.gl.show()
         for i in range(3):
             self.gl.processEvents()
diff --git a/setup.py b/setup.py
index 96afbe85dc99aa47533936d2a001b9d74717ec58..d14070351559b5e59ed677751b70c20891dbc2f4 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 """The setup script."""
-
+import os
 from setuptools import setup, find_packages
 
 with open('README.rst') as readme_file:
@@ -11,11 +11,19 @@ with open('README.rst') as readme_file:
 with open('HISTORY.rst') as history_file:
     history = history_file.read()
 
-requirements = ['Click>=6.0', ]
-
-setup_requirements = ['pytest-runner', ]
-
-test_requirements = ['pytest', ]
+# Gather requirements from requirements_dev.txt
+# TODO : We could potentially split up the test/dev dependencies later
+install_reqs = []
+requirements_path = 'requirements_dev.txt'
+with open(requirements_path, 'r') as f:
+    install_reqs += [
+        s for s in [
+            line.strip(' \n') for line in f
+        ] if not s.startswith('#') and s != ''
+    ]
+requirements = install_reqs
+setup_requirements = install_reqs
+test_requirements = install_reqs
 
 setup(
     author="S.P. Mohanty",
diff --git a/tests/test_env_observation_builder.py b/tests/test_env_observation_builder.py
index 1692a98982a787ecbadf79feb7a35593f82522e4..13f8d8f9d7df1808bfb69261ee25bf06f9da2d45 100644
--- a/tests/test_env_observation_builder.py
+++ b/tests/test_env_observation_builder.py
@@ -3,7 +3,7 @@
 
 import numpy as np
 
-from flatland.core.env_observation_builder import GlobalObsForRailEnv
+from flatland.envs.observations import GlobalObsForRailEnv
 from flatland.core.transition_map import GridTransitionMap, Grid4Transitions
 from flatland.envs.rail_env import RailEnv
 from flatland.envs.generators import rail_from_GridTransitionMap_generator
diff --git a/tests/test_environments.py b/tests/test_environments.py
index 4c55eac7afb44d95f0e49d665eeeb4bc36becea9..9c7b53b9b5876a99d7deea20da10816d81f02b65 100644
--- a/tests/test_environments.py
+++ b/tests/test_environments.py
@@ -7,7 +7,7 @@ from flatland.envs.generators import rail_from_GridTransitionMap_generator
 from flatland.envs.generators import complex_rail_generator
 from flatland.core.transitions import Grid4Transitions
 from flatland.core.transition_map import GridTransitionMap
-from flatland.core.env_observation_builder import GlobalObsForRailEnv
+from flatland.envs.observations import GlobalObsForRailEnv
 from flatland.envs.agent_utils import EnvAgent
 
 """Tests for `flatland` package."""
diff --git a/tests/test_rendertools.py b/tests/test_rendertools.py
index f6defb2de400f1a007da237b2f91ec38df5db07b..245f2f327524653b3cf03bf921f6db6b0d4b51fb 100644
--- a/tests/test_rendertools.py
+++ b/tests/test_rendertools.py
@@ -6,10 +6,10 @@ Tests for `flatland` package.
 
 from flatland.envs.rail_env import RailEnv, random_rail_generator
 import numpy as np
-<<<<<<< HEAD
-=======
+#<<<<<<< HEAD
+#=======
 # import os
->>>>>>> dc2fa1ee0244b15c76d89ab768c5e1bbd2716147
+#>>>>>>> dc2fa1ee0244b15c76d89ab768c5e1bbd2716147
 import sys
 
 import matplotlib.pyplot as plt
diff --git a/tox.ini b/tox.ini
index 5a97b7e1c5b2f09db2cca8da5e1cf9db002f26f1..1c9a170724b2ed111eac11061ba598eea52a571c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -23,7 +23,10 @@ commands = make docs
 [testenv:coverage]
 basepython = python
 whitelist_externals = make
-commands = make coverage
+commands = 
+    pip install -U pip
+    pip install -r requirements_dev.txt
+    make coverage
 
 [testenv]
 setenv =
@@ -35,6 +38,7 @@ deps =
 ;     -r{toxinidir}/requirements.txt
 commands =
     pip install -U pip
+    pip install -r requirements_dev.txt
     py.test --basetemp={envtmpdir}