Cleanup client utils

I split up `utils.py` into different files and placed them in a `utils/` directory. I also cleaned some lint errors in other parts of the client.
Here's the idea that I have for OkExceptions. So, there are three sources of error: bugs in the client, bugs in the student's code or bugs in the network/server response.

For the first one, I think the best way to solve those is to let students catch them (of course, our target will be to not have these in the first place, but this is the contingency plan). I don't think there's really any clean way to do this without suppressing errors that originate from bugs in the student's code as well.

For the second one, I think we should try to catch as many as we can and wrap them up in ClientExceptions (or something similar). Then, the ok client can do whatever it wants with them. An alternative would be to just let those surface through because that way, the students will get more experience reading error messages that aren't really nicely formatted.

For bugs in the network/server response (like serialization/deserialization errors), we should generate an error report and mostly hide it from the students.