On 30Nov2018 02:19, srinivasan <srinivasan....@gmail.com> wrote:
Thanks a lot for your quick responses, again the below line seems to
be throwing the same error, is that should I again decode the line
where am facing the issue to str? or could you please let me if there
is any alternative solution for the same or workaround in python 3.6?

Code Snippet:

   def parse_device_info(self, info_string):
       """Parse a string corresponding to a device."""
       device = {}
       block_list = ["[\x1b[0;", "removed"]
       string_valid = not any(keyword in info_string for keyword in
block_list) ---------------------------> Again this line seems to be
the same issue
[...]
   def get_paired_devices(self):
       """Return a list of tuples of paired devices."""
       try:
           out = self.get_output("paired-devices")
       except BluetoothctlError as e:
           print(e)
           return None
       else:
           paired_devices = []
           for line in out:
               device = self.parse_device_info(line)
[...]

Your problem is basicly that reading from command output gets you bytes data, not text (str) data. This is because pipes transfer bytes; that the command may issue text simply means that those bytes are an encoding of the text.

Your entire process treats the output as text, because the commands issue textual output.

Therefore, the most sensible thing to do at this point is to _decode_ the bytes into text as soon as you get them from the command, and then the rest of your programme can work in text (str) from then on.

So I would be inclined to change:

   for line in out:
       device = self.parse_device_info(line)

into (untested):

   for line_b in out:
       line = line_b.decode(errors='replace')
       device = self.parse_device_info(line)

That will turn line_b (a bytes object holding the line) into text before you try to do any parsing. From that point onward, everything is text (str) and you do not need to put any bytes->str stuff elsewhere in your programme.

Some remarks:

That decode line above uses the default bytes->str decoding, which is 'utf-8'. That is probably how your system works, but if it is not you need to adjust accordingly. If the command ussues pure ASCII you'll be fine regardless.

The decode uses "errors='replace'", which means that if the bytes data are _not_ correct UTF-8 encoded text, the decoder will put some replacement characters in the result instead of raising an exception. This simplifies your code, and since you're parsing the output anyway for infomation the replacements should show up to your eye. The default decode mode is 'strict', which would raise an exception on an invalid encoding.

Purists might decode the output stream ("out") before the for-loop, but in most encodings including UTF-8, you can split on newlines (byte code 10, ASCII NL) safely anyway, so we just split first and decode each "bytes" line individually.

In the loop I deliberately iterate over "line_b", and have the decoded text in "line", instead of doing something like:

   for line in out:
       line = line.decode(....)

That way I am always sure that I intend to talk about bytes in one place (line_b) and text (line) in another. Having variable that might contain bytes _or_ text leads to confusion and difficult debugging.

The core takeaway here is that you want to keep in mind whether you're working in bytes or text (str). Keep the division clean, that way all you other code can be written appropriately. So: the command pipe output is bytes. COnvert it to text before passing to your text parsing code. That way all the parsing code can work in text (str) and have no weird conversion logic.

Cheers,
Cameron Simpson <c...@cskk.id.au>
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to