Skip to content
This repository was archived by the owner on Jul 3, 2019. It is now read-only.

Python 3 porting process

Carl Hofmeister edited this page Jul 23, 2016 · 1 revision

Porting the rover-software to Python 3

This page documents the steps we had to take to port the rover-software to Python 3.5+ from Python 2.7. As of July 23, 2016, this is still a work in progress. Some paterns common to all modules are:

  • Change all print "Thing to print" statements to functions: print("Thing to print")
  • Import statements must include the full heirarchy, even when accessing sibling modules. For example, in the ExampleProcess.py, the line from RoverProcess import RoverProcess is changed to from roverprocess.RoverProcess import Roverprocess. I'm not sure if this is the new intended method for importing modules or just a workaround, but it works and isn't overly anoying.

These were the only changes that had to be made to main.py and no changes were necessary for the statemanager.

RoverProcess

One extra change that had to be made to the RoverProcess regarded the cleanup of the ReceiverThread. The original RoverProcess.cleanup looked like this:

def cleanup(self):
    for thread in threading.enumerate():
        if thread is not threading.current_thread():
            thread._Thread__stop()
            thread._Thread__delete()

thread._Thread__stop() is no longer available in python 3 like this, and the prefered method of stopping threads is to use the join() method. This ensures that the child thread is "joined" with it's parent, and is not left as a zombie process. Because the only thread created by the RoverProcess is the ReceiverThread, I decided to include the receiver thread as an atribute of the rover process, and explicitly join it with the rover process thread in cleanup().

In the ReceiverThread, I changed the infinate loop in the run method to instead run while ReceiverThread.quit is false. To quit the RecieverThread, set it's quit attribute to True. This doesn't quit work however as the the first statement in the while loop is a blocking method call to get data from a queue:

def run(self):
    while not self.quit:
        data = self.downlink.get()
        ...

An alternative is to use:

while not self.quit:
    try:
        data = self.downlink.get_nowait()
        ...
    except queue.Empty:
        pass
    ...

In this case the control flow works perfectly, but unfortunately ReceiverThread.run() becomes a cpu resource hog as it is continually runing through the while loop, handling thrown exceptions as fast as possible. This isn't fixed as of July 23 2016, so instead a work around for the first method is used. Here is the current Python 3 version of RoverProcess.cleanup:

def cleanup(self):
    self.receiver.quit = True
    self.receiver.join(0.25)

The call join(0.25) speceifies a timeout for the join method. This prevents the ReceiverThread from blocking the cleanup method, but may not quit the thread properly. It would be nice to fix this in the future, but for now everything works.

Servers

Not completed as of July 23, 2016.

Clone this wiki locally