Skip to content

Python3 convert braille drivers#9736

Merged
feerrenrut merged 28 commits into
threshold_py3_stagingfrom
python3-convertBrailleDrivers
Jun 28, 2019
Merged

Python3 convert braille drivers#9736
feerrenrut merged 28 commits into
threshold_py3_stagingfrom
python3-convertBrailleDrivers

Conversation

@feerrenrut

@feerrenrut feerrenrut commented Jun 13, 2019

Copy link
Copy Markdown
Contributor

Link to issue number:

Related to #9637

Summary of the issue:

The braille driver framework, and many of the drivers use strings interchangeably with bytes.

Description of how this pull request fixes the issue:

Since quite a careful approach is required to track down which literals should be bytes / vs strings and much of the surrounding logic needs to be modified I am converting the braille drivers to python 3 files-wise rather than feature-wise as we are elsewhere in the code base.

To help with this I have been using typehints and a linter to find issues. This is not perfect, it's quite likely issues have slipped through.

Testing performed:

None, this will require testing from people with devices.

Several people have voluntered to test with different devices:

Known issues with pull request:

Change log entry:

Section: New features, Changes, Bug fixes

@LeonarddeR

This comment has been minimized.

@josephsl

This comment has been minimized.

@zstanecic

This comment has been minimized.

@zstanecic

This comment has been minimized.

@LeonarddeR LeonarddeR left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are my comments for the diff until and up to the alva driver.

Comment thread source/braille.py Outdated
Comment thread source/brailleDisplayDrivers/alva.py Outdated
Comment thread source/brailleDisplayDrivers/alva.py Outdated
Comment thread source/brailleDisplayDrivers/alva.py
Comment thread source/brailleDisplayDrivers/alva.py
Comment thread source/brailleDisplayDrivers/alva.py
Comment thread source/brailleDisplayDrivers/alva.py Outdated
Comment thread source/brailleDisplayDrivers/alva.py Outdated
@feerrenrut

This comment has been minimized.

@LeonarddeR

This comment has been minimized.

@LeonarddeR

Copy link
Copy Markdown
Collaborator

I've been thinking about the several cases where you know do something like b"".join([arg, int2byte(arg2)]).

I think this can be really error prone if you don't have the proper linting tooling.

Have you considered something like this?

def createPacket(*args):
	packet = bytearray()
	for arg in args:
		if isinstance(arg, int):
			packet.append(arg)
		elif isinstance(arg, bool):
			packet.extend(boolToByte(arg))
		elif isinstance(arg, collections.abc.ByteString):
			packet.extend(arg)
		else:
			raise TypeError
	return packet

@feerrenrut

Copy link
Copy Markdown
Contributor Author

The usage of that will end up like:

createPacket(
  data[2], # an int
  data[3:6], # bytes
  b"/x67", # bytes
  "/75", # oops a unicode string, linting wont catch me.
)

I think that it hides the problem. At least with b"".join you know that everything in the list hast to be bytes (or 'bytes-like'). With a function like this, you could easily be convinced into thinking it automatically converted a case that it didn't. That said, I think the b"".join syntax is quite ugly.

@LeonarddeR LeonarddeR left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments up to and including ecoBraille

Comment thread source/brailleDisplayDrivers/baum.py
Comment thread source/brailleDisplayDrivers/baum.py Outdated
Comment thread source/brailleDisplayDrivers/baum.py Outdated
Comment thread source/brailleDisplayDrivers/baum.py Outdated
Comment thread source/brailleDisplayDrivers/baum.py
Comment thread source/brailleDisplayDrivers/baum.py Outdated
Comment thread source/brailleDisplayDrivers/brailliantB.py
Comment thread source/brailleDisplayDrivers/brailliantB.py
Comment thread source/brailleDisplayDrivers/ecoBraille.py Outdated
Comment thread source/brailleDisplayDrivers/ecoBraille.py Outdated
@LeonarddeR

LeonarddeR commented Jun 13, 2019 via email

Copy link
Copy Markdown
Collaborator

@LeonarddeR LeonarddeR left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments for the eurobraille driver

Comment thread source/brailleDisplayDrivers/eurobraille.py
Comment thread source/brailleDisplayDrivers/eurobraille.py Outdated
Comment thread source/brailleDisplayDrivers/eurobraille.py Outdated
Comment thread source/brailleDisplayDrivers/eurobraille.py Outdated
Comment thread source/brailleDisplayDrivers/eurobraille.py Outdated
Comment thread source/brailleDisplayDrivers/eurobraille.py Outdated
Comment thread source/brailleDisplayDrivers/eurobraille.py Outdated

@LeonarddeR LeonarddeR left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like I'm finished for now.

Comment thread source/brailleDisplayDrivers/freedomScientific.py Outdated
Comment thread source/brailleDisplayDrivers/freedomScientific.py Outdated
manuBytes = payload[INFO_MANU_START:INFO_MANU_END].replace(
FS_BYTE_NULL, b""
)
self._manufacturer = manuBytes.decode()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is safer to assume latin1 or cp1252 than utf-8. I think I prefer latin-1, as the 256 options in latin-1 match with the first 256 code points in Unicode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think latin-1 would match Python 2's behavior. However, assuming UTF-8 might not be a bad idea if a display will have a name including UTF-8 characters in the future. As far as I know, the first characters of latin-1/utf-8 are the same?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the first characters are the same, then can we just leave it as UTF-8? Would it be more future proof?

Comment thread source/brailleDisplayDrivers/handyTech.py Outdated
Comment thread source/brailleDisplayDrivers/handyTech.py
Comment thread source/hwIo.py
"""
@type data: bytes
"""
if not isinstance(data, bytes):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use collections.abc.ByteString here, so that bytearray is also allowed as a valid type. It is fully compatible.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, but I think it's outside of the scope of this PR to go down that road. EG finding the optimal types to allow the greatest flexibility. This PR should just be concerned with getting it working. If someone shows that it causes some perf concern to do bytes(myByteArray), or taking a bytes type only is too inflexible for some given case we can look at changing it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that before this pr, the write function just accepted everything you threwat it. You're now introducing this explicit check for bytes. I won't insist, but I really believe that it is too strict, especially given bytearray is fully compatible with bytes and they are both handled by the ByteString abstract class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reduced the types it could take to simplify verifying correctness. Taking multiple types introduces uncertainty, for instance taking an int, the code must guess how to convert it (number of bytes, byte order, signed), these are device specific and should be decided in the driver. There is certainly an argument for accepting a bytearray, however I don't see that it's necessary, and doesn't greatly impact the code. While it's tempting to try to build a general purpose library, it's much easier to get the known cases correct if we focus on those only.

especially given bytearray is fully compatible with bytes

It should be noted that a bytearray is not convertible by ctypes.create_string_buffer and will not be automatically converted to a bytes object.

Comment thread source/hwIo.py Outdated
Comment thread source/hwIo.py Outdated
Comment thread source/hwIo.py Outdated
Some extra annotations in braille.py and bdDetect.py.
Noticed that these files (braille.py and bdDetect.py) require lots more work.
@feerrenrut

Copy link
Copy Markdown
Contributor Author

Braille input fails because braille input module still calls unichr.

Thanks @josephsl I'll look at this.

@feerrenrut

Copy link
Copy Markdown
Contributor Author

The whole point of writeSize was precisely that HID reports must be a specific size, but not all packets use the full size. So, I think this warning should not be logged at all.

@jcsteh I've been looking at the docs and haven't noticed this specified in relation to WriteFile

There is this comment in the code:

# Reading any less than caps.InputReportByteLength is an error.
# On Windows 7, writing any less than caps.OutputReportByteLength is also an error.

But it doesn't tell us what error or where to get information on it. I'll look into this more on Monday, perhaps there is more information in the original commit messages / PR.

My concerns:

  • A writeSize of less than the buffer is going to result some data not being sent to the device. I suspect this is not the case, it would likely stop devices from working.
  • A writeSize of more than the buffer is going to result in reading past the end of the buffer, sending garbage.

If write size must be a fixed size, then we should be altering the size of the buffer to match and padding with something, or doing multiple writes.

Comment thread source/brailleDisplayDrivers/brailleNote.py
Comment thread source/brailleDisplayDrivers/ecoBraille.py Outdated
Comment thread source/brailleDisplayDrivers/eurobraille.py
Comment thread source/hwIo.py Outdated
Comment thread source/brailleDisplayDrivers/papenmeier_serial.py Outdated
Comment thread source/brailleDisplayDrivers/papenmeier_serial.py Outdated
Comment thread source/brailleDisplayDrivers/papenmeier_serial.py
Comment thread source/brailleDisplayDrivers/papenmeier_serial.py
Comment thread source/brailleDisplayDrivers/papenmeier_serial.py
Comment thread source/brailleDisplayDrivers/papenmeier_serial.py Outdated
@jcsteh

jcsteh commented Jun 23, 2019 via email

Copy link
Copy Markdown
Contributor

michaelDCurran added a commit that referenced this pull request Jun 24, 2019
This was the only thing causing NVDA not to run in this branch, and will be introduced exactly the same by pr #9736 anyway.
@bdorer

bdorer commented Jun 24, 2019 via email

Copy link
Copy Markdown

@michaelDCurran

michaelDCurran commented Jun 24, 2019 via email

Copy link
Copy Markdown
Member

@LeonarddeR

Copy link
Copy Markdown
Collaborator

I'm merging in current threshold_py3_staging, so we can check appveyor status for this

Leonard de Ruijter and others added 5 commits June 26, 2019 19:18
By creating the buffer manually, we can ensure that data smaller than OutputReportByteLength
will be padded with null bytes. I tested ctypes marshalling by creating
a C++ dll, loading it and calling it with ctypes.

Small refactor, only hwIo.HID devices were using _writeSize. hwIo.Bulk
took the parameter, but it was only set to 0 by the hims driver. This
failed the Truth test, and len(data) was used in this case.

The refactor allows the HID complexity to stay with the HID class.
If it becomes necessary to support buffers larger than OutputReportByteLength
further refactoring will become necessary.
Use Optional instead of Union[sometype, None]

Checked all usages of:
- ord()
- bytes()
- bytearray()
- str()

Found and fixed several issues.
@feerrenrut feerrenrut requested a review from LeonarddeR June 27, 2019 13:17
@feerrenrut

Copy link
Copy Markdown
Contributor Author

I've just re-requested reviews from @LeonarddeR and @bramd.

Just a note, we would like to merge this as soon as we can to start getting broader testing. Please focus reviewing efforts on looking for bugs / mistakes.

@LeonarddeR

Copy link
Copy Markdown
Collaborator

I have tested the following driver/display combinations over USB:

Driver Display
Handy Tech Modular Evolution 88 and Active Braille
alva Alva BC640
Papenmeier I recall an EL40C, not sture about the type number though
Eurobraille Esys 40 with firmware 3.16
Hims Braille Edge
Baum Vario Ultra 40

@LeonarddeR LeonarddeR left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the diff from last review actions, and they look ok.

@michaelDCurran

michaelDCurran commented Jun 27, 2019 via email

Copy link
Copy Markdown
Member

@michaelDCurran

Copy link
Copy Markdown
Member

Successfully used an Orbit Reader to read and navigate with NVDA, in both bluetooth and USB HID. Was also able to type braille input with #9835 merged into this branch.

@michaelDCurran

Copy link
Copy Markdown
Member

Successfully read / navigated / typed on Baum Refreshabraille 18 with both USB and blutooth.

@feerrenrut

Copy link
Copy Markdown
Contributor Author

Was the idea for this pr to also convert brailleInput.py?

Yes, actually, it seems I missed it. Perhaps we merge these two PR's then I'll take another look through brailleInput.py looking for any other issues.

@bramd

bramd commented Jun 28, 2019

Copy link
Copy Markdown
Contributor

I tested the following displays over USB:

  • Freedom Scientific Focus blue
  • HumanWare Brailliant BI 40 (serial and HID)

These work fine after applying the fixes in #9839

@feerrenrut feerrenrut merged commit 0a35c8f into threshold_py3_staging Jun 28, 2019
@nvaccessAuto nvaccessAuto added this to the 2019.3 milestone Jun 28, 2019
@feerrenrut feerrenrut deleted the python3-convertBrailleDrivers branch January 17, 2020 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants