Refactor and add Python 3 support