Re: [Tutor] Error Python version 3.6 does not support this syntax.

2018-11-29 Thread Steven D'Aprano
On Fri, Nov 30, 2018 at 02:19:25AM +0530, srinivasan wrote:
> Dear Mats,
> 
> 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?

You don't need a "workaround", you need to fix the bug in your code:


> Traceback (most recent call last):
> , in parse_device_info
> string_valid = not any(keyword in info_string for keyword in block_list)
>   File "/home/srinivasan/Downloads/bt_tests/qa/test_library/bt_tests.py",
> line 52, in 
> string_valid = not any(keyword in info_string for keyword in block_list)
> TypeError: a bytes-like object is required, not 'str'

You get that error when you wrongly try to test for a string inside a 
bytes object:

py> 'string' in b'bytes'
Traceback (most recent call last):
  File "", line 1, in 
TypeError: a bytes-like object is required, not 'str'


You fix that by making sure both objects are strings, or both are bytes, 
which ever is better for your program:

py> 'a' in 'abc'  # string in string is okay
True
py> b'a' in b'abc'  # bytes in bytes is okay
True

py> 'a' in b'abc'  # string in bytes is NOT OKAY
Traceback (most recent call last):
  File "", line 1, in 
TypeError: a bytes-like object is required, not 'str'

py> b'a' in 'abc'  # bytes in string is NOT OKAY
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'in ' requires string as left operand, not bytes


Don't mix strings and bytes. It won't work.


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Error Python version 3.6 does not support this syntax.

2018-11-29 Thread srinivasan
Dear Mats,

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

if string_valid:
try:
device_position = info_string.index("Device")
except ValueError:
pass
else:
if device_position > -1:
attribute_list = info_string[device_position:].split(" ", 2)
device = {
"mac_address": attribute_list[1],
"name": attribute_list[2]
}

return device

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)
if device:
paired_devices.append(device)

return paired_devices

if __name__ == "__main__":

print("Init bluetooth...")
bl = Bluetoothctl()
print("Ready!")
bl.start_scan()
print("Scanning for 10 seconds...")
for i in range(0, 10):
print(i)
time.sleep(1)

bl.pair("64:A2:F9:06:63:79")
print("Pairing for 10 seconds...")
for i in range(0, 10):
print(i)
time.sleep(1)

# Seems to be an issue --
bl.get_paired_devices()
print("Getting Paired devices for 10 seconds...")
for i in range(0, 10):
print(i)
time.sleep(1)

Error Logs:

Traceback (most recent call last):
, in parse_device_info
string_valid = not any(keyword in info_string for keyword in block_list)
  File "/home/srinivasan/Downloads/bt_tests/qa/test_library/bt_tests.py",
line 52, in 
string_valid = not any(keyword in info_string for keyword in block_list)
TypeError: a bytes-like object is required, not 'str'

On Fri, Nov 30, 2018 at 1:18 AM Mats Wichmann  wrote:
>
> On 11/29/18 12:20 PM, srinivasan wrote:
> > Dear Python Experts,
> >
> > With the below code snippet, I am seeing the below error, I am using
> > python 3.6, could you please what could be the issue?
>
> > self.child = pexpect.spawn("bluetoothctl", echo = False)
> ...
> > self.child.send(command + "\n")
> > time.sleep(pause)
> > start_failed = self.child.expect(["bluetooth", pexpect.EOF])
> ...
> > return self.child.before.split("\r\n")
> > --->
> > the issue seems to be here
> > line 27, in get_output
> > return self.child.before.split("\r\n")
> > TypeError: a bytes-like object is required, not 'str'
>
> your types don't match. it's Python 3 so what you get back from talking
> to an external process is a bytes object. you're calling the split
> method on that object, but passing it a string to split on - that's what
> the error is saying.  It shouldn't be any more complicated to fix that
> than to give it a byte object:
>
> return self.child.before.split(b"\r\n")
>
> or... decode the object to a str before splitting on a string.
>
> but since you're specifically splitting on lines, you may as well use
> the splitlines method instead of the split method, since that's what it
> is designed for.
>
>
>
>
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Error Python version 3.6 does not support this syntax.

2018-11-29 Thread srinivasan
Dear Python Experts,

With the below code snippet, I am seeing the below error, I am using
python 3.6, could you please what could be the issue?

Code Snippet:
---
import time
import pexpect
import subprocess
import sys

class BluetoothctlError(Exception):
"""This exception is raised, when bluetoothctl fails to start."""
pass


class Bluetoothctl:
"""A wrapper for bluetoothctl utility."""

def __init__(self):
out = subprocess.check_output("rfkill unblock bluetooth", shell = True)
self.child = pexpect.spawn("bluetoothctl", echo = False)

def get_output(self, command, pause = 0):
"""Run a command in bluetoothctl prompt, return output as a
list of lines."""
self.child.send(command + "\n")
time.sleep(pause)
start_failed = self.child.expect(["bluetooth", pexpect.EOF])

if start_failed:
raise BluetoothctlError("Bluetoothctl failed after running
" + command)

return self.child.before.split("\r\n")
--->
the issue seems to be here

def start_scan(self):
"""Start bluetooth scanning process."""
try:
out = self.get_output("scan on")
except BluetoothctlError as e:
print(e)
return None

if __name__ == "__main__":

print("Init bluetooth...")
bl = Bluetoothctl()
print("Ready!")
bl.start_scan()
print("Scanning for 10 seconds...")
for i in range(0, 10):
print(i)
time.sleep(1)

Error Logs:
-
/home/srinivasan/Downloads/bt_tests/qa/venv/bin/python
/home/srinivasan/Downloads/bt_tests/qa/test_library/bt_tests.py
Init bluetooth...
Ready!
Traceback (most recent call last):
  File "/home/srinivasan/Downloads/bt_tests/qa/test_library/bt_tests.py",
line 169, in 
bl.start_scan()
  File "/home/srinivasan/Downloads/bt_tests/qa/test_library/bt_tests.py",
line 32, in start_scan
out = self.get_output("scan on")
  File "/home/srinivasan/Downloads/bt_tests/qa/test_library/bt_tests.py",
line 27, in get_output
return self.child.before.split("\r\n")
TypeError: a bytes-like object is required, not 'str'

Process finished with exit code 1

On Wed, Nov 28, 2018 at 12:17 AM Mats Wichmann  wrote:
>
> On 11/27/18 5:50 AM, srinivasan wrote:
> > Dear Python Experts,
> >
> > As still I am newbie and learning python, I am trying to reuse the
> > Bluetoothctl wrapper in Python from the link (
> > https://gist.github.com/egorf/66d88056a9d703928f93) I am using python3.6
> > version, In pycharm editor on the bold highlighted code snippets I see the
> > error message "Python version 3.6 does not support this syntax.",
>
> once again you've posted in a way that inserts lots of extra crud, you
> avoided that last time.
>
> The syntax change is simple (and works on most older Pythons too):
>
> except ErrorType, e:
>
> becomes
>
> except ErrorType as e:
>
>
> >
> > Could you please how help me how the below highlighted lines of code can be
> > can be ported to python3.6 version?
> >
> > *except BluetoothctlError, e:*
> >
> > *print(e)*
> > *return None*
> >
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Error Python version 3.6 does not support this syntax.

2018-11-29 Thread Cameron Simpson

On 30Nov2018 02:19, srinivasan  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 
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Error Python version 3.6 does not support this syntax.

2018-11-29 Thread Mats Wichmann
On 11/29/18 12:20 PM, srinivasan wrote:
> Dear Python Experts,
> 
> With the below code snippet, I am seeing the below error, I am using
> python 3.6, could you please what could be the issue?

> self.child = pexpect.spawn("bluetoothctl", echo = False)
...
> self.child.send(command + "\n")
> time.sleep(pause)
> start_failed = self.child.expect(["bluetooth", pexpect.EOF])
...
> return self.child.before.split("\r\n")
> --->
> the issue seems to be here
> line 27, in get_output
> return self.child.before.split("\r\n")
> TypeError: a bytes-like object is required, not 'str'

your types don't match. it's Python 3 so what you get back from talking
to an external process is a bytes object. you're calling the split
method on that object, but passing it a string to split on - that's what
the error is saying.  It shouldn't be any more complicated to fix that
than to give it a byte object:

return self.child.before.split(b"\r\n")

or... decode the object to a str before splitting on a string.

but since you're specifically splitting on lines, you may as well use
the splitlines method instead of the split method, since that's what it
is designed for.





___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Error Python version 3.6 does not support this syntax.

2018-11-27 Thread Mats Wichmann
On 11/27/18 5:50 AM, srinivasan wrote:
> Dear Python Experts,
> 
> As still I am newbie and learning python, I am trying to reuse the
> Bluetoothctl wrapper in Python from the link (
> https://gist.github.com/egorf/66d88056a9d703928f93) I am using python3.6
> version, In pycharm editor on the bold highlighted code snippets I see the
> error message "Python version 3.6 does not support this syntax.",

once again you've posted in a way that inserts lots of extra crud, you
avoided that last time.

The syntax change is simple (and works on most older Pythons too):

except ErrorType, e:

becomes

except ErrorType as e:


> 
> Could you please how help me how the below highlighted lines of code can be
> can be ported to python3.6 version?
> 
> *except BluetoothctlError, e:*
> 
> *print(e)*
> *return None*
> 
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Error Python version 3.6 does not support this syntax.

2018-11-27 Thread srinivasan
Dear Python Experts,

As still I am newbie and learning python, I am trying to reuse the
Bluetoothctl wrapper in Python from the link (
https://gist.github.com/egorf/66d88056a9d703928f93) I am using python3.6
version, In pycharm editor on the bold highlighted code snippets I see the
error message "Python version 3.6 does not support this syntax.",

Could you please how help me how the below highlighted lines of code can be
can be ported to python3.6 version?

*except BluetoothctlError, e:*

*print(e)*
*return None*

Full Code snippet:
==

import time
import pexpect
import subprocess
import sys

class BluetoothctlError(Exception):
"""This exception is raised, when bluetoothctl fails to start."""
pass

class Bluetoothctl:
"""A wrapper for bluetoothctl utility."""

def __init__(self):
out = subprocess.check_output("rfkill unblock bluetooth", shell =
True)
self.child = pexpect.spawn("bluetoothctl", echo = False)

def get_output(self, command, pause = 0):
"""Run a command in bluetoothctl prompt, return output as a list of
lines."""
self.child.send(command + "\n")
time.sleep(pause)
start_failed = self.child.expect(["bluetooth", pexpect.EOF])

if start_failed:
raise BluetoothctlError("Bluetoothctl failed after running " +
command)

return self.child.before.split("\r\n")

def start_scan(self):
"""Start bluetooth scanning process."""
try:
out = self.get_output("scan on")


*except BluetoothctlError, e:print(e)return
None*

def make_discoverable(self):
"""Make device discoverable."""
try:
out = self.get_output("discoverable on")



*   except BluetoothctlError, e:print(e)return
None*
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)

if string_valid:
try:
device_position = info_string.index("Device")
except ValueError:
pass
else:
if device_position > -1:
attribute_list = info_string[device_position:].split("
", 2)
device = {
"mac_address": attribute_list[1],
"name": attribute_list[2]
}

return device

def get_available_devices(self):
"""Return a list of tuples of paired and discoverable devices."""
try:
out = self.get_output("devices")


*except BluetoothctlError, e:print(e)return
None*
else:
available_devices = []
for line in out:
device = self.parse_device_info(line)
if device:
available_devices.append(device)

return available_devices

def get_paired_devices(self):
"""Return a list of tuples of paired devices."""
try:
out = self.get_output("paired-devices")


*except BluetoothctlError, e:print(e)return
None*
else:
paired_devices = []
for line in out:
device = self.parse_device_info(line)
if device:
paired_devices.append(device)

return paired_devices

def get_discoverable_devices(self):
"""Filter paired devices out of available."""
available = self.get_available_devices()
paired = self.get_paired_devices()

return [d for d in available if d not in paired]

def get_device_info(self, mac_address):
"""Get device info by mac address."""
try:
out = self.get_output("info " + mac_address)


*except BluetoothctlError, e:print(e)return
None*
else:
return out

def pair(self, mac_address):
"""Try to pair with a device by mac address."""
try:
out = self.get_output("pair " + mac_address, 4)


*except BluetoothctlError, e:print(e)return
None*
else:
res = self.child.expect(["Failed to pair", "Pairing
successful", pexpect.EOF])
success = True if res == 1 else False
return success

def remove(self, mac_address):
"""Remove paired device by mac address, return success of the
operation."""
try:
out = self.get_output("remove " + mac_address, 3)


*except BluetoothctlError, e:print(e)return
None*
else:
res = self.child.expect(["not available", "Device has been
removed", pexpect.EOF])
success = True if res == 1 else False
return