Python3 - MonsterWeb (and Ultaborg-web)

Has anybody converted MonsterWeb and Ultraborg-web to run under Python3 ?
I'm aware to use and ThunderBorg3 and also socketserver replacing SocketServer but after lots of hours trying I've been unsuccessful getting the scripts to run from a sudu prompt.

piborg's picture

I am not aware of any already converted versions that have been made available, but I am sure I can help :)

The first thing I would suggest is that you change the port number so that you do not need sudo while debugging. Any port number over 1024 can be used with normal user permissions, I typically use 8000 when testing:

webPort = 8000  # Port number for the web-page, 80 is what web-pages normally use

You will need to add :8000 (or the number you use) to the URL to access the page, e.g.

If you can share the error(s) you are getting I can try and figure out what is not working. Most changes between Python 2 and 3 are simple (like you have already fixed), but some are a bit less obvious.

Your modded MonsterBorg looks great :)

Thanks for the port 8000 suggestion, that makes things so much easier.
The Web-server all starts up nicely but errors when I try to remotely connect.
The first error is -
File "/home/pi/PiBorg/monster-web/", line 167, in handle
reqData = reqData.split('\n')
TypeError: a bytes-like object is required, not 'str'

I'm thinking this is due to the fact Python3 strings are Unicode so I've been adding "b" and moved on to the next error.

The script now repeats "Reconnected" and "Timeout" with "Path ":/" being displayed on the top of the web page. Checking line 175 getPath has a value "b'/' is that because I've added the b to cure a previous error?

Thanks once again


piborg's picture

This is one of the awkward changes between Python 2 and 3 :)

In Python 2 there are two types for a "set of characters", the standard ASCII one 'abc' and unicode u'abc'. Like a number of other programming languages (notably C) the standard string was also used to store a set of raw byte values, like what is sent down the network cable.

In Python 3 there is only the one actual string type, it is the same as the Python 2 unicode type. To handle the set of raw byte values a bytes type was added which can be represented as a string style literal for convenience: b'abc'.

The problem you have comes down to the fact that the string type and bytes type fail an equality check with each other:

>>> 'A' == b'A'

This means that the if / elif tests need to be the correct type. For strings:

elif getPath == '/':

For bytes:

elif getPath == b'/':

If the types do not match the test will always fail, causing the code to jump to the else section at the end :)

In most cases you can convert between the two types like this:

byte_data = b'abc'
string_data = byte_data.decode()    # Defaults to UTF-8 byte values

string_data = 'abc'
byte_data = string_data .encode()    # Defaults to UTF-8 byte values


Thanks again for all the help, it's most gratefully received. I'm still having real issues with the script though.

The code seems to start up correctly and pauses at the "Press CTRL+C to terminate the web-server" prompt.
But when entering the web browser the console reports "Reconnected..." (line 83) and then "Timed out..." (line 92) with only the #unexpected page code being sent to the web browser.

I've attached the code just incase.

Maybe Python 2 wasn't so bad :)

piborg's picture

It looks like you have updated all of the startswith checks as b:

elif getPath.startswith(b'/off'):

but not the simple == equality checks:

elif getPath == b'/':

Hopefully that is all that needs fixing.

Very nearly there.....

A really big thank you for all this help, I owe you a beer or 2 :)
Everything is working now apart from the video streaming. I've attached an image of the source on the web page and that appears OK to me so I'm thinking the raspberry isn't sending the stream.
The take photo open is working correctly, so I'm a little stuck.
I've attached a print out from Thonny of some errors but these don't seem to effect the operation of the script.

Oh and 1 quick do you insert html formatted code snippets on the forum.

Really big thank you


piborg's picture

From the error message it looks like string_data is actually already of the type bytes in some cases. This causes the send function to fail, which in turn means no data is returned.

All you should need to do is check if content is already type bytes and skip the conversion when it is. I think this should do the trick:

    def send(self, content):
#       self.request.sendall(b'HTTP/1.0 200 OK\n\n%s' % (content))
        if isinstance(content, bytes):
            byte_content = content
            string_data = content
            byte_content = string_data.encode() 
#       print(string_data)
        self.request.sendall(b'HTTP/1.0 200 OK\n\n%s' % (byte_content))

As for the code snippets you need to start with:

<pre class="brush:python">

then the code, then end with


Ideally that would be enough, but any < and > symbols in the code cause trouble. They need to be swapped with &lt; and &gt; respectively.


We (you) did it, I've attached the final script as a zip if you need it in future.
A million thanks again, it really is much appreciated.


Just in case anybody needs converted to Python3 I've attached the zip

Subscribe to Comments for &quot;Python3 - MonsterWeb (and Ultaborg-web)&quot;