Friday, December 27, 2019

NVDA and Python 3 I: The Big Picture

It's been a while since posting anything here, but recent happenings with NVDA screen reader (specifically, Python 3 transition) is giving me a reason to post something about it on this blog.

One of the most profound discoveries in science is the notion of inertia - something will not change unless intervened. Discovered by Isaac Newton hundreds of years ago, this principle is not ohnly used widely in physics and other natural sciences, it is also applicable in other places, including teaching a screen reader, a necesary and crucial computer software for blind people,  to speak a different language.

I open this monologue on NVDA and Python 3 in three acts with the notion of inertia because that's what NonVisual Desktop Access would have been if it wasn't for urgency to move from Python 2 to Python 3. The NVDA of 2006 is way different than NVDA in 2019 and 2020; not only it has become the most commonly used screen reader according to a recent survey, it has "immigrated" to another country - Python 3 transition. Although many people credit me for leading this change, I'm just one player in this unfolding saga.

The purpose of this three-part monologue on NVDA and Python 3 (big picture, transition, future and lessons learned) is to describe how this project came about and to serve as a summary of how it worked out. For me, the biggest reason for posting this series is to serve as a space to talk about it, along with offering a glimpse into my own thought process regarding the transition project. It also serves as a way for me to muse about what I did right, what I should have done, and what I have learned from it.

The first installment (this post) will talk about the "big picture" - how python came about, issues, why the transition happened, and ending with explaining my involvement and advocacy for this change. The second story will talk about the actual transition work, beginning in 2016 and ending with release of NVDA 2019.3 beta, along with attempts to implement the new Python 3 mindset in the NVDA add-ons community. The third post will dive into some important lessons I have learned while investigating and leading Python 3 transition, and musings on NVDA's future after Python 3 transition.

An archeological dig into Python

One of the key things people always mention when introducing NVDA is Python programming language. Since its inception in 1990's, Python has become one of the top languages chosen by beginning programmers and seasoned experts. Due to its popularity, Python found itself employed everywhere - everything from web interfaces to security testing tools use Python, made more popular thanks to English-like syntax and a wide variety of third-party modules to choose from when enhancing a Python project.

Unfortunately, Python has two huge drawbacks: speed, and in the old days, two different ways to work with text. Python is an interpreted language, meaning it must be run by an interpreter because Python's "machine code" isn't one's and zero's (the alternative is compilation, which does transform a program from English-looking text to digits). Because of overhead with interpretation, Python, like other interpreted languages such as Perl and Basic, are slower than compiled languages such as C++.

Another issue, although it is becoming less of an issue thanks to Python 3 transition, is two different ways to represent text. Python 2 defaults to bytes, or old ways of representing text. As this assumes predominantly English texts, it had trouble understanding texts from different parts of the world. To allow Python to deal with non-English texts, a different text (string) type named Unicode was introduced (Unicode itself was defined by Unicode Consortium, with the mission of letting computers represent texts written in different languages across the world).

But you might ask, "Python seems fast enough", and "I can write 'hello world' in my native language and Python can print it". A common trick to resolving speed issue is writing parts of a project in a language that can be compiled into machine code. Python allows this through extensions written in C (note that not all Python interpreters (which there are several) can do this), along with using a module named "ctypes" to allow communication between Python code and modules (libraries) written in other languages (notably C and C++). The second issue was resolved by asking everyone to use Unicode as part of Python 3.0 (2008).

Is NVDA a Python screen reader?

Short answer: no. If that doesn't shock you, you can skip to the next section on Python 3 transition. But if you weren't shocked - an admission coming from a seasoned NVDA code contributor, you might as well read why I say NVDA is not a Python screen reader... or as some folks would say, "it is a complicated story".

NVDA is not a "pure" Python screen reader (note the word "pure"). If NVDA was written purely in Python, there would be speed issues, and people would have gone onto other things. But people say that NVDA is very responsive (under many circumstances).

The reason why NVDA is responsive is because it is actually written in a combination of Python and C++ (actually, Python, C, C++, and a little-known C++ variant called C++ with Component Extensions, or C++/CX). Python is used in vast majority of NVDA's source code and is responsible for its user interface, event loop, app module handling, configuration, among many other things. C and C++ are used for time-critical tasks such as browse mode/virtual buffer implementations and communication involved with it (in-process code), and C++/CX is used when it comes to working with WinRT components in Windows 10 that can be accessed with C++/CX (most notably, Windows OneCore speech synthesizer support). But for the purposes of this writing, I will focus on Python.

Why Python 3 for NVDA?

Back in 2006, NVDA was written in Python 2.4; in 2019, NVDA is written in Python 3.7. So why the change?

First, Python 2 is leaving (or left) this world. As of January 1, 2020, Python 2 is no more - no changes, no new features, no security fixes, and you name it. Although Python 2 code will still work, under some circumstances (such as networking applications, mission-critical devices, and other security-conscious scenarios), Python 2 will become more vulnerable to bugs and unpatched security issues. The way forward from now on is Python 3.

Second, NVDA needs to innovate to meet future demands. Although Python 2 version of NVDA will work fine for most scenarios, there are things only Python 3 can bring such as updated unicode support (better internationalization so NVDA can read text in more languages), speed improvements, security fixes, and better ways of doing things. And given how fast technology changes (or for that matter, ever-changing landscape of features and bugs), NvDA must innovate so it can enhance lives of more people in the future.

But why the delay until 2019?

In this case, a more appropriate question to ask is, "how long did the transition take?" In short, it took four years: from 2016 to 2019 (actually, 2020 as the python 3 version of NVDA is scheduled to be released to the public in early 2020). But why the delay until 2019?

The biggest cause was dependencies. NVDA needs help from other modules to work properly. Three modules in particular are needed by NVDA: wxPython (Python version of wxWidgets), SCons, and Py2exe. wxPython is used to "drive" NVDA - events, user interface, and other visible aspects of NVDA. SCons is used to guide Python through process of transforming NVDA from a combination of different things into a runnable screen reader. Py2exe is used to turn Python source code into machine code (or rather, create an executable that will run an embedded version of Python, which in turn is responsible for starting NVDA itself).

Of these three, wxPython and Py2exe are number one dependencies, and Python 3 versions for these weren't ready until 2018 and 2019, respectively. Without wxPython (and some other dependencies such as Comtypes), there is no way to bring NVDA to life - all you get is a collection of Python source code files. From wxPython side, Python 3 transition was part of Project Phoenix, an effort to modernize wxPython code and infrastructure, culminating in the release of wxPython 4 in 2018.

Although Py2exe had a version ready for Python 3, it didn't support versions above 3.4. Since the latest version of Python (at the time of transition) was 3.7, a 3.7-optimized Py2exe was needed. Thanks to hard work from a developer outside of NVDA community, Py2exe optimized for Python 3.7 was ready during Python 3 transition work (next post).

The overall Python 3 transition timeline was as follows:

* 2016: preliminary research began.
* 2017: beta version of wxPython 4/Phoenix was released, allowing source code level testing.
* 2018: NVDA includes wxPython 4.0.3, a necessary stepping stone for Python 3 transition.
* June 2019: Python 3 transition began.
* July 25, 2019: first Python 3 version of NVDA alpha snapshots released.
* December 9, 2019: NVDA 2019.3 beta 1, the first public beta of Python 3 version of NVDA was released.
* 2020: NVDA 2019.3 stable version is scheduled to be released.
* And the work goes on.

Yes, Python 3 transition work actually began in 2016 (or rather, sometime in 2015 through Project Heliopolis when I began researching dependencies). Because what happened back then factors into what we have now, I'll describe 2016 work in the next post when talking about the actual transition process. Before I close the first part, I need to talk about my involvement and advocacy for Python 3 transition in the NVDA Community.

My involvement and advocacy for Python 3 transition

I was involved in NVDA since June 2012 - first as a Korean translator, and now as a code contributor and add-on author/reviewer. The story of Korean language and translations and how that motivated me to become a full-time NVDA community member might be showcased in a future post (Korean language and my immigration experience ties into another series of blog posts I'm planning).

Prior to NVDA community involvement, I was known as the "BrailleNote expert/professor" - acting as sort of a tech support person at my local high school when it came to dealing with BrailleNote issues (back when I was a high school student; my work caught the attention of a writer for a blindness technology magazine and was interviewed when I was 17 about my experiences; that was twelve years ago). Even then and now my philosophy for teaching and supporting something is, "use something for its full potential". And since I was (and to some degree, still) a kinetic learner, I would learn internals of a product by first reading about it and experimenting (they involved performing commands that are not usually documented in the user guide). Perhaps that was one of the reasons that drew me to major in computer science at UC Riverside (interesting experiences; no bachelor's degree from UCR but learn some important lessons about computing and life).

Perhaps my "teaching experience" on HumanWare's notetaker product line and curiosity about technology carried with me through my years in the NVDA Community until now. Even Python 3, for which I was aware of when I began writing NVDA add-ons in 2013, was an experiment at first. The more I learned about advantages and drawbacks of Python 3 versus Python 2, along with an announcement from Python Software Foundation (PSF) that Python 2 is leaving this world in 2020, gave me more reasons to learn Python 3 on my own and think about moving NVDA to Python 3.

Sometime in 2015, I began looking into what's involved in moving a project from Python 2 to 3, specifically when it came to NVDA. As a 25-year-old blind student who also had to deal with studying a different major at a different college then, I had to balance between adjusting to my new major (communication studies) and NVDA work. Thankfully, I did adjust well into my new major, but wasn't going great when it came to Python 3 research. And then Windows 10 hit the scene in July 2015, and as a Windows Insider (I joined Windows InsiderProgram in October 2014), I and millions of other Insiders were first to receive Version 1507 (build 10240) in July, and helping the blind community adjust to Windows 10 kept me busy for the next few months.

In the midst of chaos then, I still thought about Python 3. During the course of my research, I read about wxPython's Project Phoenix and bits here and there about other projects. Back in 2015, I didn't understand the literature in front of me; it wasn't until 2016 when I seriously began experimenting with Python 3 and alpha releases of Phoenix that I began to have "aha" moments. I'll detail what happened then in the next post, but suffice to say that more experiments and reviewing other projects convinced me that Python 3 was the way forward.

Then came 2017 and first beta release of wxPython Phoenix/version 4. By then I was grasping python 3, and began experimenting with Phoenix. I continued experimenting until 2018 when I submitted wxPython 4 compatibility code to NV Access as a pull request.

By then I have become proficient in Python 3 and added my voice to a growing sentiment that NVDA should be powered by Python 3 in the future. Although I did meet resistance from people who believed that Python 2 version of NVDA should be maintained for a long time, I felt that with impending end of Python 2 support, it was time for everyone to change their mindset about moving to Python 3. Eventually the community agreed, and Python 3 transition work is now history.

For me, Python 3 was and still is the future, and moving to Python 3 would allow NVDA to unlock its full potential. Although NVDA 2019.3 does not fully utilize power of Python 3, it is on its way to doing so, akin to changing inertia of something - slowly at first, but picking up speed. The actual transition process and the thought process that went into it is coming up soon.

Until then, Happy New Year.

//JL