faizan
faizan

Reputation: 1

MiniEdit GUI Unable to export python file

Miniedit GUI is showing error (as given below) when trying to export l2 script. I am running the Miniedit python file as python 3.6 as it was showing errors when opening with default python installed 2.7.

Error message:

File "/usr/lib/python3.6/tkinter/__init__.py"

TypeError: a byte -like object is required, not 'str'

Screenshot of the full error message

Upvotes: 0

Views: 2265

Answers (6)

Nelson aka SpOOKY
Nelson aka SpOOKY

Reputation: 147

Refer this comment on github. It solved for me.

Basically...

For error in exporting python script

line 2019 needs to be changed in miniedit.py

  • instead of for widget, item in self.widgetToItem: it should be for widget, item in self.widgetToItem.items(): because items() must be called on dict and it is correct everwhere else other than this line.

For error in saving as .mn file

remove self.convertJsonUnicode call in line 1444 of mininet.py

  • instead of loadedTopology = self.convertJsonUnicode(json.load(f)) just use loadedTopology = json.load(f). The loadedTopology dict keys are loaded as bytes when using convertJsonUnicode which should actually be strings.

Upvotes: -1

CYBER GAMING
CYBER GAMING

Reputation: 1

I am using python3 version 3.10.12. Ubuntu 22.04

This is the error i was getting in terminal

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.10/tkinter/__init__.py", line 1921, in __call__
    return self.func(*args)
  File "/home/muhammad/mininet/examples/miniedit.py", line 1508, in loadTopology
    hosts = loadedTopology['hosts']
KeyError: 'hosts'

I think the problem lies in the way miniedit saves and load the topology information. The topology information is loaded in dictionary whose key values are in byte-string. Notice b' prepended with every key-value. Also take note of b'hosts' key.

loadedTopology = {
    b'application': {
        b'dpctl': b'',
        b'ipBase': b'10.0.0.0/8',
        b'netflow': {
            b'nflowAddId': b'0',
            b'nflowTarget': b'',
            b'nflowTimeout': b'600'
        },
        b'openFlowVersions': {
            b'ovsOf10': b'1',
            b'ovsOf11': b'0',
            b'ovsOf12': b'0',
            b'ovsOf13': b'0'
        },
        b'sflow': {
            b'sflowHeader': b'128',
            b'sflowPolling': b'30',
            b'sflowSampling': b'400',
            b'sflowTarget': b''
        },
        b'startCLI': b'0',
        b'switchType': b'ovs',
        b'terminalType': b'xterm'
    },
    b'controllers': [],
    b'hosts': [
        {
            b'number': b'1',
            b'opts': {
                b'hostname': b'h1',
                b'nodeNum': 1,
                b'sched': b'host'
            },
            b'x': b'130.0',
            b'y': b'147.0'
        },
        {
            b'number': b'2',
            b'opts': {
                b'hostname': b'h2',
                b'nodeNum': 2,
                b'sched': b'host'
            },
            b'x': b'150.0',
            b'y': b'280.0'
        }
    ],
    b'links': [],
    b'switches': [],
    b'version': b'3'
}

Now open miniedit.py file in vs code the file is located in mininet/examples folder. Go to line something 1507. The starting code would look like this

hosts = loadedTopology['hosts']
        # print(hosts)
        for host in hosts:
            nodeNum = host['number']
        # more code ....

You can see the line

    hosts = loadedTopology['hosts']

It expects key ['hosts'] but since loaded topology dictionary is in byte strings it we are giving it b'hosts' as key which it does not wants.

To change this we need to decode each byte-string in loadedTopology dictionary to regular strings recursively.

Go to line something 1447. Where the loadTopology function is defined like

    def loadTopology( self ):
        "Load command."
        c = self.canvas
       # more code ...

above loadTopology definition add another function which we would use for decoding

    def decode_byte_strings(self,data):
        if isinstance(data, dict):
            decoded_dict = {}
            for key, value in data.items():
                if isinstance(key, bytes):
                    key = key.decode()
                if isinstance(value, bytes):
                    value = value.decode()
                decoded_dict[key] = self.decode_byte_strings(value)
            return decoded_dict
        elif isinstance(data, list):
            return [self.decode_byte_strings(item) for item in data]
        else:
            return data

Now we just need to use it in loadTopology decode_byte_strings function. See the last line in code below

    def decode_byte_strings(self,data):
        if isinstance(data, dict):
            decoded_dict = {}
            for key, value in data.items():
                if isinstance(key, bytes):
                    key = key.decode()
                if isinstance(value, bytes):
                    value = value.decode()
                decoded_dict[key] = self.decode_byte_strings(value)
            return decoded_dict
        elif isinstance(data, list):
            return [self.decode_byte_strings(item) for item in data]
        else:
            return data
        
    def loadTopology( self ):
        "Load command."
        c = self.canvas

        myFormats = [
            ('Mininet Topology','*.mn'),
            ('All Files','*'),
        ]
        f = tkFileDialog.askopenfile(filetypes=myFormats, mode='rb')
        if f is None:
            return
        self.newTopology()
        loadedTopology = self.convertJsonUnicode(json.load(f))

        # Here we have used decoding function
        loadedTopology = self.decode_byte_strings(loadedTopology)

See the last line in code. We have used the functions. Now the loadedTopology dictionary will contain regular strings

Now save the file and run miniedit.py.

That's how i solved my problem, by the way this is my second answer on stackoverflow. so i am currently not that great at providing concise answers. I hope i explained in as much relevant and concise way as i could

Thanks for reading. Have a nice Day.

Upvotes: 0

Ameer Mosa Al-Sadi
Ameer Mosa Al-Sadi

Reputation: 1

I used Python 2 to run Mininedit on Mininet 2.3.0, and it is working properly.

Command below:

$ sudo -E python2 ~/mininet/examples/miniedit.py

Upvotes: 0

Sarmad
Sarmad

Reputation: 31

I had the same problem, all I did was change the default file path to desktop /usr/lib/python2.7/dist-packages/mininet/examples path to Desktop and it works, so all you have to do is change the file path

Upvotes: 0

Abb
Abb

Reputation: 11

Change the line 1452 to:

self.appPrefs.update(loadedTopology['application'])

And the lines 1686 and 1705 to:

f = open(fileName, 'w')

for more information Fix python3 compatibility issues in miniedit

Upvotes: 1

Go to where miniedit.py locate then open it with text editor.

Go to line 1702 and change to:

f = open(fileName, 'w')

Upvotes: 0

Related Questions