0

I'm updating a script written in python 2 to python 3 which I'm learning while trying to use. this wxpython controlled LED class is causing an error: (TypeError: Expected a list of bytes objects.) I believe the problem stems from this list

xpm = ['17 17 5 1', # width height ncolors chars_per_pixel
        '0 c %s' % corner_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        'X c %s' % base_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        '- c %s' % light_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        '= c %s' % shadow_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        '* c %s' % highlight_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii')]

xpm += [s.strip() for s in ascii_led.splitlines()]

self.bmp = wx.Bitmap(xpm)

OG code came from the code below, which is from http://code.activestate.com/recipes/533125-wxpython-led-control/

# Based on C++ code by Thomas Monjalon
# Developed by Daniel Eloff on 14/9/07

import wx

def change_intensity(color, fac):
    rgb = [color.Red(), color.Green(), color.Blue()]
    for i, intensity in enumerate(rgb):
        rgb[i] = min(int(round(intensity*fac, 0)), 255)

    return wx.Color(*rgb)    

class LED(wx.Control):
    def __init__(self, parent, id=-1, colors=[wx.Colour(220, 10, 10), wx.Colour(250, 200, 0), wx.Colour(10, 220, 10)],
                 pos=(-1,-1), style=wx.NO_BORDER):
        size = (17, 17)
        wx.Control.__init__(self, parent, id, pos, size, style)
        self.MinSize = size

        self._colors = colors
        self._state = -1
        self.SetState(0)
        self.Bind(wx.EVT_PAINT, self.OnPaint, self)

    def SetState(self, i):
        if i < 0:
            raise ValueError, 'Cannot have a negative state value.'
        elif i >= len(self._colors):
            raise IndexError, 'There is no state with an index of %d.' % i
        elif i == self._state:
            return

        self._state = i
        base_color = self._colors[i]
        light_color = change_intensity(base_color, 1.15)
        shadow_color = change_intensity(base_color, 1.07)
        highlight_color = change_intensity(base_color, 1.25)

        ascii_led = '''
        000000-----000000      
        0000---------0000
        000-----------000
        00-----XXX----=00
        0----XX**XXX-===0
        0---X***XXXXX===0
        ----X**XXXXXX====
        ---X**XXXXXXXX===
        ---XXXXXXXXXXX===
        ---XXXXXXXXXXX===
        ----XXXXXXXXX====
        0---XXXXXXXXX===0
        0---=XXXXXXX====0
        00=====XXX=====00
        000===========000
        0000=========0000
        000000=====000000
        '''.strip()

        xpm = ['17 17 5 1', # width height ncolors chars_per_pixel
               '0 c None', 
               'X c %s' % base_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
               '- c %s' % light_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
               '= c %s' % shadow_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
               '* c %s' % highlight_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii')]

        xpm += [s.strip() for s in ascii_led.splitlines()]

        self.bmp = wx.BitmapFromXPMData(xpm)

        self.Refresh()

    def GetState(self):
        return self._state

    State = property(GetState, SetState)

    def OnPaint(self, e):
        dc = wx.PaintDC(self)
        dc.DrawBitmap(self.bmp, 0, 0, True)
dboy
  • 1,004
  • 2
  • 16
  • 24
  • 1
    Welcome to SO! Check out the [tour] and [ask]. What's your question? Are you aware that [Python 2 and 3 handle strings totally differently](https://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit)? Please [edit] the question to have a descriptive title, and to clarify what you're asking. LMK when you do and I'll undo my downvote. – wjandrea Apr 15 '20 at 16:13
  • My bad, obviously you're asking how to fix it. You should still set a better title though. – wjandrea Apr 15 '20 at 16:23
  • What is the issue, exactly? Have you done any debugging? Please provide a [mcve], as well as the entire error message. – AMC Apr 15 '20 at 16:52

4 Answers4

2

bytes and str were synonyms in Python 2 but have become incompatible types in Python 3. The constructor for wx.Bitmap expects a list of bytes, so you should make sure that every item in the list you pass to it is a bytes object by either using bytes literals or encoding strings into bytes:

xpm = [b'17 17 5 1', # width height ncolors chars_per_pixel
        b'0 c %s' % corner_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        b'X c %s' % base_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        b'- c %s' % light_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        b'= c %s' % shadow_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii'),
        b'* c %s' % highlight_color.GetAsString(wx.C2S_HTML_SYNTAX).encode('ascii')]

xpm += [s.strip().encode('ascii') for s in ascii_led.splitlines()]
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • hey thanks for the advice how might I accomplish that? I started learning python last week so I'm struggling a bit. – MemePresident Apr 15 '20 at 18:14
  • You're welcome. Have you tried the code example I included above? Note the added `b` prefix to each string literal to make it a bytes literal, and the added call to `encode` in the last line. – blhsing Apr 15 '20 at 19:41
  • I had not noticed the difference, I just tried it and it did not change the error it still says It expects a list of bytes. thank you for your help though – MemePresident Apr 16 '20 at 12:52
0

The doc on wx isn't very clear on how exactly it wants this input to be formatted, but you can try just encoding each of your strs in the default utf-8 before passing the list to the Bitmap constructor:

self.bmp = wx.Bitmap([s.encode() for s in xpm])
Samwise
  • 68,105
  • 3
  • 30
  • 44
  • Thank for trying to help I tried that and it caused a system error which tossed a whole error pop up which is more than my attempts got so cool. the window said, "XPM: malformed colour definition '0 c b#808080' ' at line 1! – MemePresident Apr 15 '20 at 18:10
0

Bytes objects are different in Python 3. See this documentation page.

tcdejong
  • 88
  • 6
0

You can pass the bytes string into list() to convert back:

list(bytes(xpm))
Mahsa Hassankashi
  • 2,086
  • 1
  • 15
  • 25