From 858bf1837406ace6afa5faa7d0f25be98591d841 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sun, 26 Aug 2012 19:47:00 +0100 Subject: [PATCH 001/362] Initial Import. --- COPYING.txt | 340 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 40 ++++++ addon/manifest.ini | 6 + sconstruct | 57 ++++++++ 4 files changed, 443 insertions(+) create mode 100644 COPYING.txt create mode 100644 README.md create mode 100644 addon/manifest.ini create mode 100644 sconstruct diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f045dac --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# NVDA Add-on Scons Template + +This package contains a basic template structure for NVDA add-on development, building and distribution. +For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). + +Coryright (C) 2012 - Rui Batista. + +This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. + +## Features + +This template provides the following features you can use to help NVDA add-on development: +* Automatic add-on package creation, with naming and version loaded from the add-on manifest file. +* Compilation of gettext mo files before distribution, when needed. + +## Requirements + +You need the following software to use this code on your NVDA add-ons development: + +- a Python distribution (2.7 or greater is recomended). Check the [Python Website](http://www.python.org) for Windows Installers. +- Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. +- GNU Gettext tools, if you want to have localization support on your add-on - Recomended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). + +## Usage + +To create a new NVDA add-on, taking advantage of this template: + +- Create an empty folder to put your add-on's files +- Copy the **addon** folder and **SCONSTRUCT** file to the created folder +- On the created folder, Change the **addon\manifest.inn** file so it reflects your add-on information. Don't leave any field as is. +- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need on your particular add-on package. +- Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. +- To package the add-on for distribution, open a command line, change to the folder that as the **SCONSTRUCT** file and run the **scons** command. The created add-on, if no errors happen, is placed on the current directory. + +Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. + + +## Author Information + +If you have any issues or whatever please use github or drop me an email to ruiandrebatista at gmail dot com. diff --git a/addon/manifest.ini b/addon/manifest.ini new file mode 100644 index 0000000..3cd1813 --- /dev/null +++ b/addon/manifest.ini @@ -0,0 +1,6 @@ +name = addon-template +summary = NVDA sample add-on template +description = Change name, summary, version, author and description for your specific add-on. +author = Put your name here +url = http://example.com +version = x.y.z diff --git a/sconstruct b/sconstruct new file mode 100644 index 0000000..cf45f29 --- /dev/null +++ b/sconstruct @@ -0,0 +1,57 @@ +# NVDA add-on template SCONSTRUCT file +#Copyright (C) 2012 Rui Batista +#This file is covered by the GNU General Public License. +#See the file COPYIG.txt for more details. + +import os.path +import zipfile +import configobj + +manifest_path = os.path.join("addon", "manifest.ini") +manifest = configobj.ConfigObj(manifest_path, encoding="utf-8") + +env = Environment(ENV=os.environ, + version=manifest['version'], +) + + +addonFile = "%s-%s.%s" % (manifest['name'], manifest['version'], "nvda-addon") + +def addonGenerator(target, source, env, for_signature): + action = env.Action(lambda target, source, env : createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, + lambda target, source, env : "Generating Addon %s" % target[0]) + return action + +env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) + + +env['BUILDERS']['gettextMoFile']=env.Builder( + action=env.Action(["msgfmt -o $TARGETS $SOURCES"], lambda t, s, e : "Compiling translation %s" % s[0]), + suffix=".mo", + src_suffix=".po" +) + + +def createAddonBundleFromPath(path, dest): + """ Creates a bundle from a directory that contains a a addon manifest file.""" + basedir = os.path.abspath(path) + with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as z: + # FIXME: the include/exclude feature may or may not be useful. Also python files can be pre-compiled. + for dir, dirnames, filenames in os.walk(basedir): + relativePath = os.path.relpath(dir, basedir) + for filename in filenames: + pathInBundle = os.path.join(relativePath, filename) + absPath = os.path.join(dir, filename) + z.write(absPath, pathInBundle) + return dest + +addon = env.NVDAAddon(addonFile, env.Dir('addon')) + +#Allow all add-on gettext po files to be compiled in source/locale. +pos = env.Glob(os.path.join("addon", "locale", "*", "LC_MESSAGES", "nvda.po")) +for po in pos: + moFile=env.gettextMoFile(po) + env.Depends(moFile, po) + env.Depends(addon, moFile) + +env.Default(addon) From 589d863971613271d1074267f1a911c2527a9f81 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Thu, 30 Aug 2012 16:19:36 +0100 Subject: [PATCH 002/362] Add pot target to the template, and better dependency checking. Customize buildVars.py for your own needs. --- buildVars.py | 13 +++++++++++++ sconstruct | 29 ++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 buildVars.py diff --git a/buildVars.py b/buildVars.py new file mode 100644 index 0000000..8cf824d --- /dev/null +++ b/buildVars.py @@ -0,0 +1,13 @@ + +# Build customizations +# Change this file instead of sconstruct, whenever possible. + +import os.path + +# Define the python files that are the sources of your add-on. +# You can use glob expressions here, they will be expanded. +pythonSources = [] + +# Files that contain strings for translation. Usually your python sources +i18nSources = pythonSources + diff --git a/sconstruct b/sconstruct index cf45f29..e9437a1 100644 --- a/sconstruct +++ b/sconstruct @@ -1,12 +1,15 @@ # NVDA add-on template SCONSTRUCT file #Copyright (C) 2012 Rui Batista #This file is covered by the GNU General Public License. -#See the file COPYIG.txt for more details. +#See the file COPYING.txt for more details. +import operator import os.path import zipfile import configobj +import buildVars + manifest_path = os.path.join("addon", "manifest.ini") manifest = configobj.ConfigObj(manifest_path, encoding="utf-8") @@ -31,6 +34,9 @@ env['BUILDERS']['gettextMoFile']=env.Builder( src_suffix=".po" ) +env['BUILDERS']['gettextPotFile']=env.Builder( + action=env.Action(["xgettext -o $TARGETS $SOURCES"], lambda t, s, e : "Generating pot file %s" % t[0]), + sufix=".pot") def createAddonBundleFromPath(path, dest): """ Creates a bundle from a directory that contains a a addon manifest file.""" @@ -45,13 +51,26 @@ def createAddonBundleFromPath(path, dest): z.write(absPath, pathInBundle) return dest -addon = env.NVDAAddon(addonFile, env.Dir('addon')) +def expandGlobs(files): + l = [env.Glob(pattern) for pattern in files] + return reduce(operator.add, l, []) -#Allow all add-on gettext po files to be compiled in source/locale. -pos = env.Glob(os.path.join("addon", "locale", "*", "LC_MESSAGES", "nvda.po")) +addon = env.NVDAAddon(addonFile, env.Dir('addon')) +#Allow all NVDA's gettext po files to be compiled in source/locale +pos = env.Glob(os.path.join("addon", "locale", "*", "LC_MESSAGES", "*.po")) for po in pos: - moFile=env.gettextMoFile(po) + moFile=env.gettextMoFile(po) env.Depends(moFile, po) env.Depends(addon, moFile) +pythonFiles = expandGlobs(buildVars.pythonSources) +env.Depends(addon, pythonFiles) + +# Pot target +i18nFiles = expandGlobs(buildVars.i18nSources) +pot = env.gettextPotFile("%s.pot" % manifest['name'], i18nFiles) +env.Alias('pot', pot) +env.Depends(pot, i18nFiles) + +env.Depends(addon, manifest_path) env.Default(addon) From 3bf720a741fe4d7201015a512c6667b303acb72d Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Thu, 30 Aug 2012 16:22:45 +0100 Subject: [PATCH 003/362] Update documentation to refere the pot target. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f045dac..7119467 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,9 @@ This package is distributed under the terms of the GNU General Public License, v This template provides the following features you can use to help NVDA add-on development: * Automatic add-on package creation, with naming and version loaded from the add-on manifest file. -* Compilation of gettext mo files before distribution, when needed. +* Compilation of gettext mo files before distribution, when needed.file for the needs of your add-on. +- To generate a gettext pot file, please run scons pot. a .pot file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. + ## Requirements @@ -31,7 +33,7 @@ To create a new NVDA add-on, taking advantage of this template: - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need on your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. - To package the add-on for distribution, open a command line, change to the folder that as the **SCONSTRUCT** file and run the **scons** command. The created add-on, if no errors happen, is placed on the current directory. - +- You can customize variables in the buildVars.py Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From 948b8c91e902e02114c7b9fcc529a8d3d0de5460 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sun, 9 Sep 2012 16:01:19 +0100 Subject: [PATCH 004/362] fix small linguistic issues. --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7119467..c015b2c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This package contains a basic template structure for NVDA add-on development, building and distribution. For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). -Coryright (C) 2012 - Rui Batista. +Copyright (C) 2012 - Rui Batista. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. @@ -17,22 +17,22 @@ This template provides the following features you can use to help NVDA add-on de ## Requirements -You need the following software to use this code on your NVDA add-ons development: +You need the following software to use this code for your NVDA add-ons development: -- a Python distribution (2.7 or greater is recomended). Check the [Python Website](http://www.python.org) for Windows Installers. +- a Python distribution (2.7 or greater is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. - Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. -- GNU Gettext tools, if you want to have localization support on your add-on - Recomended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). +- GNU Gettext tools, if you want to have localization support on your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). ## Usage To create a new NVDA add-on, taking advantage of this template: -- Create an empty folder to put your add-on's files +- Create an empty folder which will hold your add-on's files - Copy the **addon** folder and **SCONSTRUCT** file to the created folder - On the created folder, Change the **addon\manifest.inn** file so it reflects your add-on information. Don't leave any field as is. -- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need on your particular add-on package. +- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. -- To package the add-on for distribution, open a command line, change to the folder that as the **SCONSTRUCT** file and run the **scons** command. The created add-on, if no errors happen, is placed on the current directory. +- To package the add-on for distribution, open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if no errors happen, is placed in the current directory. - You can customize variables in the buildVars.py Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From 82fd3da3b1a63eb118fcb5e253c71d5ace819b17 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sat, 22 Sep 2012 15:58:48 +0100 Subject: [PATCH 005/362] add template .gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6aa22b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc +*.mo +*.pot +*.nvda-adon From 121a9a2c0c94ce529d2079127e25605abb5775eb Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sat, 22 Sep 2012 16:17:35 +0100 Subject: [PATCH 006/362] .gitignore, fix typo. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6aa22b4..87b2568 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *.pyc *.mo *.pot -*.nvda-adon +*.nvda-addon From 7882a7bf63a08bdbe8eeedc4545aad63d2c36723 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sun, 7 Oct 2012 08:38:06 +0100 Subject: [PATCH 007/362] update .gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 87b2568..46dfdbb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.mo *.pot *.nvda-addon +.sconsign.dblite From 85cbbc3650a757a1a98fe53aeecb4628e183d6f1 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sun, 7 Oct 2012 10:10:01 +0100 Subject: [PATCH 008/362] set some xgettext pot headers. --- sconstruct | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index e9437a1..1b48409 100644 --- a/sconstruct +++ b/sconstruct @@ -35,8 +35,10 @@ env['BUILDERS']['gettextMoFile']=env.Builder( ) env['BUILDERS']['gettextPotFile']=env.Builder( - action=env.Action(["xgettext -o $TARGETS $SOURCES"], lambda t, s, e : "Generating pot file %s" % t[0]), - sufix=".pot") + action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' -c -o $TARGETS $SOURCES" % + ("nvda-translations@freelists.org", manifest['name'], manifest['version']) + ], lambda t, s, e : "Generating pot file %s" % t[0]), + suffix=".pot") def createAddonBundleFromPath(path, dest): """ Creates a bundle from a directory that contains a a addon manifest file.""" From 1d3373297d3f8e24e4d62e7b392252e3e1547006 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sat, 13 Oct 2012 02:07:53 +0100 Subject: [PATCH 009/362] Make add-on explicitly dependent on all python sources. --- sconstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index e9437a1..141ec51 100644 --- a/sconstruct +++ b/sconstruct @@ -64,7 +64,8 @@ for po in pos: env.Depends(addon, moFile) pythonFiles = expandGlobs(buildVars.pythonSources) -env.Depends(addon, pythonFiles) +for file in pythonFiles: + env.Depends(addon, file) # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) From fad27031ea8325901ba390a5139a26030b6c37da Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Tue, 30 Oct 2012 14:47:36 +0000 Subject: [PATCH 010/362] Make manifest.ini a template in the top directory (manifest.ini.tpl) --- addon/manifest.ini => manifest.ini.tpl | 8 +++---- sconstruct | 32 ++++++++++++++++++-------- 2 files changed, 27 insertions(+), 13 deletions(-) rename addon/manifest.ini => manifest.ini.tpl (59%) diff --git a/addon/manifest.ini b/manifest.ini.tpl similarity index 59% rename from addon/manifest.ini rename to manifest.ini.tpl index 3cd1813..ae3cf26 100644 --- a/addon/manifest.ini +++ b/manifest.ini.tpl @@ -1,6 +1,6 @@ -name = addon-template +name = {addon-name} summary = NVDA sample add-on template description = Change name, summary, version, author and description for your specific add-on. -author = Put your name here -url = http://example.com -version = x.y.z +author = "{addon-author}" +url = {addon-url} +version = {addon-version} diff --git a/sconstruct b/sconstruct index 141ec51..b2578a1 100644 --- a/sconstruct +++ b/sconstruct @@ -10,23 +10,24 @@ import configobj import buildVars -manifest_path = os.path.join("addon", "manifest.ini") -manifest = configobj.ConfigObj(manifest_path, encoding="utf-8") -env = Environment(ENV=os.environ, - version=manifest['version'], -) +env = Environment(ENV=os.environ) -addonFile = "%s-%s.%s" % (manifest['name'], manifest['version'], "nvda-addon") +addonFile = env.File("{addon-name}-{addon-version}.nvda-addon".format(**buildVars.addon_info)) def addonGenerator(target, source, env, for_signature): action = env.Action(lambda target, source, env : createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, lambda target, source, env : "Generating Addon %s" % target[0]) return action -env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) +def manifestGenerator(target, source, env, for_signature): + action = env.Action(lambda target, source, env : generateManifest(source[0].abspath, target[0].abspath) and None, + lambda target, source, env : "Generating manifest %s" % target[0]) + return action +env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) +env['BUILDERS']['NVDAManifest'] = Builder(generator=manifestGenerator) env['BUILDERS']['gettextMoFile']=env.Builder( action=env.Action(["msgfmt -o $TARGETS $SOURCES"], lambda t, s, e : "Compiling translation %s" % s[0]), @@ -51,6 +52,13 @@ def createAddonBundleFromPath(path, dest): z.write(absPath, pathInBundle) return dest +def generateManifest(source, dest): + with open(source, "r") as f: + manifest_template = f.read() + manifest = manifest_template.format(**buildVars.addon_info) + with open(dest, "w") as f: + f.write(manifest) + def expandGlobs(files): l = [env.Glob(pattern) for pattern in files] return reduce(operator.add, l, []) @@ -69,9 +77,15 @@ for file in pythonFiles: # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) -pot = env.gettextPotFile("%s.pot" % manifest['name'], i18nFiles) +pot = env.gettextPotFile("%s.pot" % "${addon-name}", i18nFiles) env.Alias('pot', pot) env.Depends(pot, i18nFiles) -env.Depends(addon, manifest_path) +manifestFiles = expandGlobs([os.path.join("addon", "manifest.ini"), os.path.join("addon", "local", "*", "manifest.ini")]) +for file in manifestFiles: + env.Depends(addon, file) + +# Generate Manifest path +env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl")) + env.Default(addon) From 2389692c748baa893ea1194cd763de324749dc80 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Tue, 30 Oct 2012 14:48:09 +0000 Subject: [PATCH 011/362] Add a new add_info variable to the buildVars.py file --- buildVars.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index 8cf824d..0517b54 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,6 +1,18 @@ - # Build customizations -# Change this file instead of sconstruct, whenever possible. +# Change this file instead of sconstruct or manifest files, whenever possible. + +# Add-on information variables +addon_info = { +# add-on Name + "addon-name" : "addon-template", + # version + "addon-version" : "x.y.z", + # Author(s) + "addon-author" : "name ", +# URL for the add-on documentation support +"addon-url" : None +} + import os.path From 202c3c959584e77fec5936a7461b714110822881 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Tue, 30 Oct 2012 14:58:04 +0000 Subject: [PATCH 012/362] Updated README with further instructions. --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7119467..51a89a5 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ This package is distributed under the terms of the GNU General Public License, v ## Features This template provides the following features you can use to help NVDA add-on development: -* Automatic add-on package creation, with naming and version loaded from the add-on manifest file. +* Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). +* Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. * Compilation of gettext mo files before distribution, when needed.file for the needs of your add-on. - To generate a gettext pot file, please run scons pot. a .pot file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. @@ -28,15 +29,16 @@ You need the following software to use this code on your NVDA add-ons developmen To create a new NVDA add-on, taking advantage of this template: - Create an empty folder to put your add-on's files -- Copy the **addon** folder and **SCONSTRUCT** file to the created folder -- On the created folder, Change the **addon\manifest.inn** file so it reflects your add-on information. Don't leave any field as is. +- Copy the **addon** folder, the **buildVars.py** file, and the **SCONSTRUCT** file to the created folder +- On the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, version, author and url). +- Change the **manifest.ini.tpl** file so it further reflects your add-on information that can be translated 8summary and description). Don't leave any field as is. Values between braces are variables replaced from the **addon_info** variable you have set. - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need on your particular add-on package. -- Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. +- Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. Manifest translations must be ptu on **addon\locale\\manifest.ini**. - To package the add-on for distribution, open a command line, change to the folder that as the **SCONSTRUCT** file and run the **scons** command. The created add-on, if no errors happen, is placed on the current directory. -- You can customize variables in the buildVars.py +- You can further customize variables in the **buildVars.py** file. Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. ## Author Information -If you have any issues or whatever please use github or drop me an email to ruiandrebatista at gmail dot com. +If you have any issues or whatever, please use github, bibtbucket, the NVDA development list, or just drop me an email to ruiandrebatista at gmail dot com. From 19cbd902ffd7200f100d2b1eb7eadb3cd3468c8c Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sun, 18 Nov 2012 18:24:39 +0000 Subject: [PATCH 013/362] Geerate translated manifest files from the po translation file so codec errors can be definitly avoided. --- buildVars.py | 12 +++++++++++- sconstruct | 46 +++++++++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/buildVars.py b/buildVars.py index 0517b54..e174f87 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,10 +1,20 @@ # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. +# Full getext (please don't change) +_ = lambda x : x + # Add-on information variables addon_info = { # add-on Name "addon-name" : "addon-template", + # Add-on description + # TRANSLATORS: Summary for this add-on to be shown on installation and add-on informaiton. + "addon-summary" : _("Add-on quick summary"), + # Add-on description + # Translators: Long description to be shown for this add-on on installation and add-on information + "addon-description" : _(""" description for the add-on. +It can span multiple lines."""), # version "addon-version" : "x.y.z", # Author(s) @@ -21,5 +31,5 @@ pythonSources = [] # Files that contain strings for translation. Usually your python sources -i18nSources = pythonSources +i18nSources = pythonSources + ["buildVars.py"] diff --git a/sconstruct b/sconstruct index b2578a1..6ddfc49 100644 --- a/sconstruct +++ b/sconstruct @@ -3,6 +3,7 @@ #This file is covered by the GNU General Public License. #See the file COPYING.txt for more details. +import gettext import operator import os.path import zipfile @@ -26,8 +27,17 @@ def manifestGenerator(target, source, env, for_signature): lambda target, source, env : "Generating manifest %s" % target[0]) return action + +def translatedManifestGenerator(target, source, env, for_signature): + dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) + lang = os.path.basename(dir) + action = env.Action(lambda target, source, env : generateTranslatedManifest(lang, target[0].abspath) and None, + lambda target, source, env : "Generating translated manifest %s" % target[0]) + return action + env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) env['BUILDERS']['NVDAManifest'] = Builder(generator=manifestGenerator) +env['BUILDERS']['NVDATranslatedManifest'] = Builder(generator=translatedManifestGenerator) env['BUILDERS']['gettextMoFile']=env.Builder( action=env.Action(["msgfmt -o $TARGETS $SOURCES"], lambda t, s, e : "Compiling translation %s" % s[0]), @@ -57,19 +67,32 @@ def generateManifest(source, dest): manifest_template = f.read() manifest = manifest_template.format(**buildVars.addon_info) with open(dest, "w") as f: - f.write(manifest) + f.write(manifest.encode("utf-8")) + +def generateTranslatedManifest(language, out): + _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext + template = u"""summary = \"{addon-summary}\" +description = \"{addon-description}\"""" + d = {k : _(buildVars.addon_info[k]) for k in ("addon-summary", "addon-description")} + result = template.format(**d) + with open(out, "w") as f: + f.write(result.encode("utf-8")) def expandGlobs(files): l = [env.Glob(pattern) for pattern in files] return reduce(operator.add, l, []) addon = env.NVDAAddon(addonFile, env.Dir('addon')) -#Allow all NVDA's gettext po files to be compiled in source/locale -pos = env.Glob(os.path.join("addon", "locale", "*", "LC_MESSAGES", "*.po")) -for po in pos: - moFile=env.gettextMoFile(po) - env.Depends(moFile, po) - env.Depends(addon, moFile) + +langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] + +#Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated +for dir in langDirs: + poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) + moFile=env.gettextMoFile(poFile) + env.Depends(moFile, poFile) + translatedManifest = env.NVDATranslatedManifest(dir.File("manifest.ini"), moFile) + env.Depends(addon, [translatedManifest, moFile]) pythonFiles = expandGlobs(buildVars.pythonSources) for file in pythonFiles: @@ -77,15 +100,12 @@ for file in pythonFiles: # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) -pot = env.gettextPotFile("%s.pot" % "${addon-name}", i18nFiles) +pot = env.gettextPotFile("%s.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) env.Alias('pot', pot) env.Depends(pot, i18nFiles) -manifestFiles = expandGlobs([os.path.join("addon", "manifest.ini"), os.path.join("addon", "local", "*", "manifest.ini")]) -for file in manifestFiles: - env.Depends(addon, file) - # Generate Manifest path -env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl")) +manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl")) +env.Depends(addon, manifest) env.Default(addon) From 12dac4309ff518f92f349a44376d193b340fe887 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sun, 18 Nov 2012 18:35:05 +0000 Subject: [PATCH 014/362] Updated README. --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 51a89a5..0da0f2f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # NVDA Add-on Scons Template -This package contains a basic template structure for NVDA add-on development, building and distribution. +This package contains a basic template structure for NVDA add-on development, building, distribution and localization. For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). -Coryright (C) 2012 - Rui Batista. +Copyright (C) 2012 - Rui Batista. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. @@ -12,9 +12,9 @@ This package is distributed under the terms of the GNU General Public License, v This template provides the following features you can use to help NVDA add-on development: * Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. -* Compilation of gettext mo files before distribution, when needed.file for the needs of your add-on. +* Compilation of gettext mo files before distribution, when needed. - To generate a gettext pot file, please run scons pot. a .pot file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. - +* Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVar.py is included in i18nFiles. ## Requirements @@ -29,11 +29,10 @@ You need the following software to use this code on your NVDA add-ons developmen To create a new NVDA add-on, taking advantage of this template: - Create an empty folder to put your add-on's files -- Copy the **addon** folder, the **buildVars.py** file, and the **SCONSTRUCT** file to the created folder -- On the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, version, author and url). -- Change the **manifest.ini.tpl** file so it further reflects your add-on information that can be translated 8summary and description). Don't leave any field as is. Values between braces are variables replaced from the **addon_info** variable you have set. +- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file and the **SCONSTRUCT** file to the created folder +- On the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need on your particular add-on package. -- Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. Manifest translations must be ptu on **addon\locale\\manifest.ini**. +- Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. - To package the add-on for distribution, open a command line, change to the folder that as the **SCONSTRUCT** file and run the **scons** command. The created add-on, if no errors happen, is placed on the current directory. - You can further customize variables in the **buildVars.py** file. Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From 916cf7322a46b126ce39b8a5c30f52cae47c769d Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Tue, 20 Nov 2012 11:09:05 +0100 Subject: [PATCH 015/362] small corrections to readme. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0956139..89d9c5f 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,12 @@ You need the following software to use this code for your NVDA add-ons developme To create a new NVDA add-on, taking advantage of this template: -- Create an empty folder to put your add-on's files +- Create an empty folder to hold the files for your add-on. - Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file and the **SCONSTRUCT** file to the created folder -- On the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). -- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need on your particular add-on package. +- In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). +- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. -- To package the add-on for distribution, open a command line, change to the folder that as the **SCONSTRUCT** file and run the **scons** command. The created add-on, if no errors happen, is placed on the current directory. +- To package the add-on for distribution, open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. - You can further customize variables in the **buildVars.py** file. Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From de924e7f7732c7808284ae0116dc009c8ae2e591 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Tue, 20 Nov 2012 11:49:24 +0000 Subject: [PATCH 016/362] Corrected errors --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index ad20440..df33265 100644 --- a/sconstruct +++ b/sconstruct @@ -47,7 +47,7 @@ env['BUILDERS']['gettextMoFile']=env.Builder( env['BUILDERS']['gettextPotFile']=env.Builder( action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' -c -o $TARGETS $SOURCES" % - ("nvda-translations@freelists.org", manifest['name'], manifest['version']) + ("nvda-translations@freelists.org", buildVars.addon_info['addon-name'], buildVars.addon_info['addon-version']) ], lambda t, s, e : "Generating pot file %s" % t[0]), suffix=".pot") From 3dea1384173f49839a972357e92f481c98549b20 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Tue, 20 Nov 2012 14:43:55 +0000 Subject: [PATCH 017/362] Added manifest variables. --- manifest.ini.tpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.ini.tpl b/manifest.ini.tpl index ae3cf26..3f28f69 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -1,6 +1,6 @@ name = {addon-name} -summary = NVDA sample add-on template -description = Change name, summary, version, author and description for your specific add-on. +summary = "{addon-summary}" +description = "{addon-description}" author = "{addon-author}" url = {addon-url} version = {addon-version} From 565215219bce30719acf4bb9ac500b6a5a41e1b2 Mon Sep 17 00:00:00 2001 From: James Teh Date: Fri, 23 Nov 2012 10:02:47 +1000 Subject: [PATCH 018/362] sconstruct: expandGlobs: Use nested list comprehension instead of reduce and operator.add. --- sconstruct | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index df33265..926e3da 100644 --- a/sconstruct +++ b/sconstruct @@ -4,7 +4,6 @@ #See the file COPYING.txt for more details. import gettext -import operator import os.path import zipfile import configobj @@ -81,8 +80,7 @@ description = \"{addon-description}\"""" f.write(result.encode("utf-8")) def expandGlobs(files): - l = [env.Glob(pattern) for pattern in files] - return reduce(operator.add, l, []) + return [f for pattern in files for f in env.Glob(pattern)] addon = env.NVDAAddon(addonFile, env.Dir('addon')) From 3ac54b3e35c76f95221d71690098b42adfd3d74b Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Wed, 28 Nov 2012 15:13:50 +0000 Subject: [PATCH 019/362] Add triple quotes to description in manifest files so tey can span multipe lines. --- manifest.ini.tpl | 2 +- sconstruct | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.ini.tpl b/manifest.ini.tpl index 3f28f69..8093a3f 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -1,6 +1,6 @@ name = {addon-name} summary = "{addon-summary}" -description = "{addon-description}" +description = """{addon-description}""" author = "{addon-author}" url = {addon-url} version = {addon-version} diff --git a/sconstruct b/sconstruct index 926e3da..fa48f03 100644 --- a/sconstruct +++ b/sconstruct @@ -73,7 +73,7 @@ def generateManifest(source, dest): def generateTranslatedManifest(language, out): _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext template = u"""summary = \"{addon-summary}\" -description = \"{addon-description}\"""" +description = \"\"\"{addon-description}\"\"\"""" d = {k : _(buildVars.addon_info[k]) for k in ("addon-summary", "addon-description")} result = template.format(**d) with open(out, "w") as f: From e71c50c039a736b5176afc07ec90fb6ebf741b36 Mon Sep 17 00:00:00 2001 From: Patrick ZAJDA Date: Mon, 3 Dec 2012 11:05:28 +0100 Subject: [PATCH 020/362] Add a template named manifest-translated.ini.tpl for translated manifest files. --- manifest-translated.ini.tpl | 2 ++ sconstruct | 17 ++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 manifest-translated.ini.tpl diff --git a/manifest-translated.ini.tpl b/manifest-translated.ini.tpl new file mode 100644 index 0000000..4750635 --- /dev/null +++ b/manifest-translated.ini.tpl @@ -0,0 +1,2 @@ +summary = "{addon-summary}" +description = """{addon-description}""" diff --git a/sconstruct b/sconstruct index fa48f03..9f45f6e 100644 --- a/sconstruct +++ b/sconstruct @@ -30,7 +30,7 @@ def manifestGenerator(target, source, env, for_signature): def translatedManifestGenerator(target, source, env, for_signature): dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) lang = os.path.basename(dir) - action = env.Action(lambda target, source, env : generateTranslatedManifest(lang, target[0].abspath) and None, + action = env.Action(lambda target, source, env : generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None, lambda target, source, env : "Generating translated manifest %s" % target[0]) return action @@ -70,12 +70,15 @@ def generateManifest(source, dest): with open(dest, "w") as f: f.write(manifest.encode("utf-8")) -def generateTranslatedManifest(language, out): +def generateTranslatedManifest(source, language, out): _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext - template = u"""summary = \"{addon-summary}\" -description = \"\"\"{addon-description}\"\"\"""" - d = {k : _(buildVars.addon_info[k]) for k in ("addon-summary", "addon-description")} - result = template.format(**d) + #template = u"""summary = \"{addon-summary}\" +#description = \"\"\"{addon-description}\"\"\"""" + #d = {k : _(buildVars.addon_info[k]) for k in ("addon-summary", "addon-description")} + #result = template.format(**d) + with open(source, "r") as f: + manifest_template = f.read() + result = manifest_template.format(**buildVars.addon_info) with open(out, "w") as f: f.write(result.encode("utf-8")) @@ -91,7 +94,7 @@ for dir in langDirs: poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) moFile=env.gettextMoFile(poFile) env.Depends(moFile, poFile) - translatedManifest = env.NVDATranslatedManifest(dir.File("manifest.ini"), moFile) + translatedManifest = env.NVDATranslatedManifest(dir.File("manifest.ini"), [moFile, os.path.join("manifest-translated.ini.tpl")]) env.Depends(addon, [translatedManifest, moFile]) pythonFiles = expandGlobs(buildVars.pythonSources) From 1d30b391c10d844c04cc9297211a6a88220bd62f Mon Sep 17 00:00:00 2001 From: Patrick ZAJDA Date: Mon, 3 Dec 2012 11:14:41 +0100 Subject: [PATCH 021/362] Remove useless comments. --- sconstruct | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sconstruct b/sconstruct index 9f45f6e..a288e8a 100644 --- a/sconstruct +++ b/sconstruct @@ -72,10 +72,6 @@ def generateManifest(source, dest): def generateTranslatedManifest(source, language, out): _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext - #template = u"""summary = \"{addon-summary}\" -#description = \"\"\"{addon-description}\"\"\"""" - #d = {k : _(buildVars.addon_info[k]) for k in ("addon-summary", "addon-description")} - #result = template.format(**d) with open(source, "r") as f: manifest_template = f.read() result = manifest_template.format(**buildVars.addon_info) From 6459b286d1c01c6b336d4416cf14a53ae147ee39 Mon Sep 17 00:00:00 2001 From: Patrick ZAJDA Date: Mon, 3 Dec 2012 12:54:52 +0100 Subject: [PATCH 022/362] Update README.md. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89d9c5f..740eb95 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ You need the following software to use this code for your NVDA add-ons developme To create a new NVDA add-on, taking advantage of this template: - Create an empty folder to hold the files for your add-on. -- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file and the **SCONSTRUCT** file to the created folder +- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl and the **SCONSTRUCT** file to the created folder - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. From 5ec8b17deca798c94dbf345324bd04592bdf0d36 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Wed, 5 Dec 2012 16:48:03 +0000 Subject: [PATCH 023/362] Corrected bug introduced when extracting translated manfiest emplate (it wasn't using gettext at al). Use codecs module facilities to handle utf-8 encoding. --- sconstruct | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sconstruct b/sconstruct index a288e8a..9a24edd 100644 --- a/sconstruct +++ b/sconstruct @@ -3,6 +3,7 @@ #This file is covered by the GNU General Public License. #See the file COPYING.txt for more details. +import codecs import gettext import os.path import zipfile @@ -64,19 +65,22 @@ def createAddonBundleFromPath(path, dest): return dest def generateManifest(source, dest): - with open(source, "r") as f: + with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() manifest = manifest_template.format(**buildVars.addon_info) - with open(dest, "w") as f: - f.write(manifest.encode("utf-8")) + with codecs.open(dest, "w", "utf-8") as f: + f.write(manifest) def generateTranslatedManifest(source, language, out): _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext - with open(source, "r") as f: + vars = {} + for var in ("addon-summary", "addon-description"): + vars[var] = _(buildVars.addon_info[var]) + with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() - result = manifest_template.format(**buildVars.addon_info) - with open(out, "w") as f: - f.write(result.encode("utf-8")) + result = manifest_template.format(**vars) + with codecs.open(out, "w", "utf-8") as f: + f.write(result) def expandGlobs(files): return [f for pattern in files for f in env.Glob(pattern)] From bc73753bb1fb4e67c6c7f47a054f00fa405f0b27 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sun, 6 Jan 2013 12:18:07 +0100 Subject: [PATCH 024/362] fixing indentation. --- buildVars.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/buildVars.py b/buildVars.py index e174f87..8d9140c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -6,21 +6,21 @@ # Add-on information variables addon_info = { -# add-on Name + # add-on Name "addon-name" : "addon-template", # Add-on description # TRANSLATORS: Summary for this add-on to be shown on installation and add-on informaiton. "addon-summary" : _("Add-on quick summary"), # Add-on description # Translators: Long description to be shown for this add-on on installation and add-on information - "addon-description" : _(""" description for the add-on. + "addon-description" : _("""Description for the add-on. It can span multiple lines."""), # version "addon-version" : "x.y.z", # Author(s) "addon-author" : "name ", -# URL for the add-on documentation support -"addon-url" : None + # URL for the add-on documentation support + "addon-url" : None } From d346f5eb9feed6f42b33e4f80afdcda8c2a92b01 Mon Sep 17 00:00:00 2001 From: Patrick ZAJDA Date: Sat, 19 Jan 2013 12:00:22 +0100 Subject: [PATCH 025/362] buildVars.py: fixed a little spelling error (informaiton instead of information). --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 8d9140c..9c416ac 100644 --- a/buildVars.py +++ b/buildVars.py @@ -9,7 +9,7 @@ # add-on Name "addon-name" : "addon-template", # Add-on description - # TRANSLATORS: Summary for this add-on to be shown on installation and add-on informaiton. + # TRANSLATORS: Summary for this add-on to be shown on installation and add-on information. "addon-summary" : _("Add-on quick summary"), # Add-on description # Translators: Long description to be shown for this add-on on installation and add-on information From 310e7a7a70590d4a9ba54f56db61b90a0c433327 Mon Sep 17 00:00:00 2001 From: beqa Date: Fri, 8 Mar 2013 11:53:44 +0400 Subject: [PATCH 026/362] added new goal mergePot to be used by updateAddons.sh, which only shows differences when messages change, not line numbers or header fields --- sconstruct | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 9a24edd..508c8f1 100644 --- a/sconstruct +++ b/sconstruct @@ -50,6 +50,11 @@ env['BUILDERS']['gettextPotFile']=env.Builder( ("nvda-translations@freelists.org", buildVars.addon_info['addon-name'], buildVars.addon_info['addon-version']) ], lambda t, s, e : "Generating pot file %s" % t[0]), suffix=".pot") +env['BUILDERS']['gettextMergePotFile']=env.Builder( + action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' --omit-header --no-location -c -o $TARGETS $SOURCES" % + ("nvda-translations@freelists.org", buildVars.addon_info['addon-name'], buildVars.addon_info['addon-version']) + ], lambda t, s, e : "Generating pot file %s" % t[0]), + suffix=".pot") def createAddonBundleFromPath(path, dest): """ Creates a bundle from a directory that contains a a addon manifest file.""" @@ -61,7 +66,7 @@ def createAddonBundleFromPath(path, dest): for filename in filenames: pathInBundle = os.path.join(relativePath, filename) absPath = os.path.join(dir, filename) - z.write(absPath, pathInBundle) + if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle) return dest def generateManifest(source, dest): @@ -106,6 +111,9 @@ i18nFiles = expandGlobs(buildVars.i18nSources) pot = env.gettextPotFile("%s.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) env.Alias('pot', pot) env.Depends(pot, i18nFiles) +mergePot = env.gettextMergePotFile("%s.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) +env.Alias('mergePot', mergePot) +env.Depends(mergePot, i18nFiles) # Generate Manifest path manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl")) From f10650b866a433c16453a7525df6ca97cf04d4fe Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sat, 9 Mar 2013 10:56:14 +0100 Subject: [PATCH 027/362] buildVars.py, add missinv excludedFiles variable. --- buildVars.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/buildVars.py b/buildVars.py index 9c416ac..29bbc9e 100644 --- a/buildVars.py +++ b/buildVars.py @@ -33,3 +33,6 @@ # Files that contain strings for translation. Usually your python sources i18nSources = pythonSources + ["buildVars.py"] +# Files that will be ignored when building the nvda-addon file +# Paths are relative to the addon directory, not to the root directory of your addon sources. +excludedFiles = [] From 7e63be4712bd8d389d6e1d887ca12b55ea0f8369 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sat, 9 Mar 2013 11:31:45 +0100 Subject: [PATCH 028/362] updated .gitignore. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 46dfdbb..3a59e11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -*.pyc +*.ini *.mo *.pot +*.pyc *.nvda-addon .sconsign.dblite From b611278736adfbb35b6333a56fa545b05f2642d8 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 13 Mar 2013 03:39:12 -0700 Subject: [PATCH 029/362] Sconstruct - improved pot generation. --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 508c8f1..4366cca 100644 --- a/sconstruct +++ b/sconstruct @@ -111,7 +111,7 @@ i18nFiles = expandGlobs(buildVars.i18nSources) pot = env.gettextPotFile("%s.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) env.Alias('pot', pot) env.Depends(pot, i18nFiles) -mergePot = env.gettextMergePotFile("%s.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) +mergePot = env.gettextMergePotFile("%s-merge.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) env.Alias('mergePot', mergePot) env.Depends(mergePot, i18nFiles) From a9204496d2e3bfb4d5b00894968bc9a04659ad27 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Fri, 15 Mar 2013 16:21:45 +0100 Subject: [PATCH 030/362] Added .gitattributes to ensure consistant line endings. --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ceae4de --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set default behaviour, in case users don't have core.autocrlf set. +* text=auto From ba5474ec9539e4496ec1f7adfe50205ec9cfd0a8 Mon Sep 17 00:00:00 2001 From: Tyler Spivey Date: Tue, 16 Apr 2013 07:20:06 -0700 Subject: [PATCH 031/362] Mention copying .gitattributes and .gitignore in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 740eb95..c173c24 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ You need the following software to use this code for your NVDA add-ons developme To create a new NVDA add-on, taking advantage of this template: - Create an empty folder to hold the files for your add-on. -- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl and the **SCONSTRUCT** file to the created folder +- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, .gitignore and .gitattributes files to the created folder - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. From 23e3b6657ac0e1c79470f245d2ba940969feada0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 20 May 2013 20:53:14 +0200 Subject: [PATCH 032/362] Support for addons documentation: initial commit. --- README.md | 2 ++ docHandler.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 docHandler.py diff --git a/README.md b/README.md index c173c24..1a6d239 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ To create a new NVDA add-on, taking advantage of this template: - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. +- Documentation files must be placed into addon\doc\/fileName, readme.html by default. +- You can copy docHandler.py to a globalPlugins or appModules folder. Then import it and use docHandler.openDocPath() to open the documentation file corresponding to NVDA's current language, or English by default. - To package the add-on for distribution, open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. - You can further customize variables in the **buildVars.py** file. diff --git a/docHandler.py b/docHandler.py new file mode 100644 index 0000000..da9c1d5 --- /dev/null +++ b/docHandler.py @@ -0,0 +1,41 @@ +# -*- coding: UTF-8 -*- + +# docHandler: module for managing addons documentation +# See: http://community.nvda-project.org/ticket/2694 + +import os +import languageHandler + +_addonDir = os.path.join(os.path.dirname(__file__), "..") # The root of an addon folder +_docFileName = "readme.html" # The name of an addon documentation file + +def getDocFolder(addonDir=_addonDir): + langs = [languageHandler.getLanguage(), "en"] + for lang in langs: + docFolder = os.path.join(addonDir, "doc", lang) + if os.path.isdir(docFolder): + return docFolder + if "_" in lang: + tryLang = lang.split("_")[0] + docFolder = os.path.join(addonDir, "doc", tryLang) + if os.path.isdir(docFolder): + return docFolder + if tryLang == "en": + break + if lang == "en": + break + return None + +def getDocPath(docFileName=_docFileName): + docPath = getDocFolder() + if docPath is not None: + docFile = os.path.join(docPath, docFileName) + if os.path.isfile(docFile): + docPath = docFile + return docPath + +def openDocPath(): + try: + os.startfile(getDocPath()) + except WindowsError: + pass \ No newline at end of file From c6e89822152ba8ac07aa4d081b6c2693af7e2c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 23 May 2013 20:18:30 +0200 Subject: [PATCH 033/362] Added a global plugin to append Open addons documentation item to NVDA's help menu. --- README.md | 2 +- addon/globalPlugins/docHandler.py | 70 +++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 addon/globalPlugins/docHandler.py diff --git a/README.md b/README.md index 1a6d239..b203bcb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ To create a new NVDA add-on, taking advantage of this template: - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. - Documentation files must be placed into addon\doc\/fileName, readme.html by default. -- You can copy docHandler.py to a globalPlugins or appModules folder. Then import it and use docHandler.openDocPath() to open the documentation file corresponding to NVDA's current language, or English by default. +- Assign a unique name to **docHandler.py** file, found under **addon\globalPlugins**, for instance **yourAddonName_docHandler**. This plugin will append an item to NVDA's help menu for opening your addon documentation in the current language, or English by default. - To package the add-on for distribution, open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. - You can further customize variables in the **buildVars.py** file. diff --git a/addon/globalPlugins/docHandler.py b/addon/globalPlugins/docHandler.py new file mode 100644 index 0000000..cafcc5a --- /dev/null +++ b/addon/globalPlugins/docHandler.py @@ -0,0 +1,70 @@ +# -*- coding: UTF-8 -*- + +# docHandler: module for managing addons documentation +# See: http://community.nvda-project.org/ticket/2694 + +import os +import languageHandler +import addonHandler +import globalPluginHandler +import gui +import wx + +addonHandler.initTranslation() + +_addonDir = os.path.join(os.path.dirname(__file__), "..") # The root of an addon folder +_docFileName = "readme.html" # The name of an addon documentation file +_curAddon = addonHandler.Addon(_addonDir) # Addon instance +_addonSummary = _curAddon.manifest['summary'] +_addonVersion = _curAddon.manifest['version'] +_addonName = _curAddon.manifest['name'] + +def getDocFolder(addonDir=_addonDir): + langs = [languageHandler.getLanguage(), "en"] + for lang in langs: + docFolder = os.path.join(addonDir, "doc", lang) + if os.path.isdir(docFolder): + return docFolder + if "_" in lang: + tryLang = lang.split("_")[0] + docFolder = os.path.join(addonDir, "doc", tryLang) + if os.path.isdir(docFolder): + return docFolder + if tryLang == "en": + break + if lang == "en": + break + return None + +def getDocPath(docFileName=_docFileName): + docPath = getDocFolder() + if docPath is not None: + docFile = os.path.join(docPath, docFileName) + if os.path.isfile(docFile): + docPath = docFile + return docPath + +def openDocPath(): + try: + os.startfile(getDocPath()) + except WindowsError: + pass + +class GlobalPlugin(globalPluginHandler.GlobalPlugin): + + def __init__(self): + super(globalPluginHandler.GlobalPlugin, self).__init__() + self.help = gui.mainFrame.sysTrayIcon.helpMenu + self.helpItem = self.help.Append(wx.ID_ANY, "{summary} {version}".format(summary=_addonSummary, version=_addonVersion), + # Translators: Tooltip for an addon menu item. + _("Open documentation for %s") % _addonName) + gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onHelp, self.helpItem) + + def onHelp(self, evt): + openDocPath() + + def terminate(self): + try: + self.help.RemoveItem(self.helpItem) + except wx.PyDeadObjectError: + pass From 2a20f8b543bcbf14a0fef492c9e3a28d1dd84155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 25 May 2013 01:46:23 +0200 Subject: [PATCH 034/362] Now docHandler is copied to globalPlugins folder and renamed as yourAddonName_docHandler.py automatically. --- README.md | 1 - docHandler.py | 31 ++++++++++++++++++++++++++++++- sconstruct | 23 ++++++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a6d239..a907e1e 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ To create a new NVDA add-on, taking advantage of this template: - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. - Documentation files must be placed into addon\doc\/fileName, readme.html by default. -- You can copy docHandler.py to a globalPlugins or appModules folder. Then import it and use docHandler.openDocPath() to open the documentation file corresponding to NVDA's current language, or English by default. - To package the add-on for distribution, open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. - You can further customize variables in the **buildVars.py** file. diff --git a/docHandler.py b/docHandler.py index da9c1d5..cafcc5a 100644 --- a/docHandler.py +++ b/docHandler.py @@ -5,9 +5,19 @@ import os import languageHandler +import addonHandler +import globalPluginHandler +import gui +import wx + +addonHandler.initTranslation() _addonDir = os.path.join(os.path.dirname(__file__), "..") # The root of an addon folder _docFileName = "readme.html" # The name of an addon documentation file +_curAddon = addonHandler.Addon(_addonDir) # Addon instance +_addonSummary = _curAddon.manifest['summary'] +_addonVersion = _curAddon.manifest['version'] +_addonName = _curAddon.manifest['name'] def getDocFolder(addonDir=_addonDir): langs = [languageHandler.getLanguage(), "en"] @@ -38,4 +48,23 @@ def openDocPath(): try: os.startfile(getDocPath()) except WindowsError: - pass \ No newline at end of file + pass + +class GlobalPlugin(globalPluginHandler.GlobalPlugin): + + def __init__(self): + super(globalPluginHandler.GlobalPlugin, self).__init__() + self.help = gui.mainFrame.sysTrayIcon.helpMenu + self.helpItem = self.help.Append(wx.ID_ANY, "{summary} {version}".format(summary=_addonSummary, version=_addonVersion), + # Translators: Tooltip for an addon menu item. + _("Open documentation for %s") % _addonName) + gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onHelp, self.helpItem) + + def onHelp(self, evt): + openDocPath() + + def terminate(self): + try: + self.help.RemoveItem(self.helpItem) + except wx.PyDeadObjectError: + pass diff --git a/sconstruct b/sconstruct index 4366cca..f84cd82 100644 --- a/sconstruct +++ b/sconstruct @@ -5,6 +5,8 @@ import codecs import gettext +import shutil +import os import os.path import zipfile import configobj @@ -57,8 +59,27 @@ env['BUILDERS']['gettextMergePotFile']=env.Builder( suffix=".pot") def createAddonBundleFromPath(path, dest): - """ Creates a bundle from a directory that contains a a addon manifest file.""" + """ Creates a bundle from a directory that contains an addon manifest file.""" basedir = os.path.abspath(path) + plugindir = os.path.join(basedir, "globalPlugins") + docFilename = "{addonName}_docHandler.py".format(addonName=buildVars.addon_info["addon-name"]) + if not os.path.isdir(plugindir): + try: + os.makedirs(plugindir) + except: + pass + try: + shutil.copy("docHandler.py", plugindir) + except: + pass + if not os.path.isfile(docFilename): + curdir = os.getcwd() + os.chdir(plugindir) + try: + os.rename("docHandler.py", docFilename) + except: + pass + os.chdir(curdir) with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as z: # FIXME: the include/exclude feature may or may not be useful. Also python files can be pre-compiled. for dir, dirnames, filenames in os.walk(basedir): From e2f009c142a6c76602ac84a5cd2e16b74436a327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 25 May 2013 11:49:48 +0200 Subject: [PATCH 035/362] Help menu will be added just for addons containing doc\en folder. --- README.md | 2 +- sconstruct | 37 ++++++++++++++++++------------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index a907e1e..4e3a13f 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ To create a new NVDA add-on, taking advantage of this template: - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. -- Documentation files must be placed into addon\doc\/fileName, readme.html by default. +- Documentation files must be placed into addon\doc\/fileName, readme.html by default. Don't use **docHandler.py** or **yourAddonName_docHandler.py** as file names contained in **globalPlugins** if your addon include documentation files; they will be removed to create a menu item for opening your doc addon, under NVDA's help menu. - To package the add-on for distribution, open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. - You can further customize variables in the **buildVars.py** file. diff --git a/sconstruct b/sconstruct index f84cd82..e6a7a4a 100644 --- a/sconstruct +++ b/sconstruct @@ -58,28 +58,27 @@ env['BUILDERS']['gettextMergePotFile']=env.Builder( ], lambda t, s, e : "Generating pot file %s" % t[0]), suffix=".pot") +def createAddonHelp(dir): + docdir = os.path.join(dir, "doc", "en") + if not os.path.isdir(docdir): + return + docFilename = "{addonName}_docHandler.py".format(addonName=buildVars.addon_info["addon-name"]) + plugindir = os.path.join(dir, "globalPlugins") + docPath = os.path.join(plugindir, docFilename) + if not os.path.isdir(plugindir): + os.makedirs(plugindir) + shutil.copy("docHandler.py", plugindir) + curdir = os.getcwd() + if os.path.isfile(docPath): + os.unlink(docPath) + os.chdir(plugindir) + os.rename("docHandler.py", docFilename) + os.chdir(curdir) + def createAddonBundleFromPath(path, dest): """ Creates a bundle from a directory that contains an addon manifest file.""" basedir = os.path.abspath(path) - plugindir = os.path.join(basedir, "globalPlugins") - docFilename = "{addonName}_docHandler.py".format(addonName=buildVars.addon_info["addon-name"]) - if not os.path.isdir(plugindir): - try: - os.makedirs(plugindir) - except: - pass - try: - shutil.copy("docHandler.py", plugindir) - except: - pass - if not os.path.isfile(docFilename): - curdir = os.getcwd() - os.chdir(plugindir) - try: - os.rename("docHandler.py", docFilename) - except: - pass - os.chdir(curdir) + createAddonHelp(basedir) with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as z: # FIXME: the include/exclude feature may or may not be useful. Also python files can be pre-compiled. for dir, dirnames, filenames in os.walk(basedir): From 786a4ba1bcd520653dfd589892e5dbd9e16d6598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 25 May 2013 19:21:00 +0200 Subject: [PATCH 036/362] Added to readme.md docHandler.py as file to be copied. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e3a13f..abfc62b 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ You need the following software to use this code for your NVDA add-ons developme To create a new NVDA add-on, taking advantage of this template: - Create an empty folder to hold the files for your add-on. -- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, .gitignore and .gitattributes files to the created folder +- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, .gitignore, .gitattributes and **docHandler.py** files to the created folder. - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. From 969d0d4b556086460b1d967b632e9f64266092ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Fri, 31 May 2013 16:15:26 +0200 Subject: [PATCH 037/362] Removed BOM in docHandler. --- docHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docHandler.py b/docHandler.py index cafcc5a..8aa718b 100644 --- a/docHandler.py +++ b/docHandler.py @@ -1,4 +1,4 @@ -# -*- coding: UTF-8 -*- +# -*- coding: UTF-8 -*- # docHandler: module for managing addons documentation # See: http://community.nvda-project.org/ticket/2694 From a13fd7fd6c0c869963f76dfdb8c4b88e31ef0580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Fri, 7 Jun 2013 23:04:07 +0200 Subject: [PATCH 038/362] Corrected message in docHandler. Added this file to i18nSources. --- buildVars.py | 2 +- docHandler.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index 29bbc9e..f626c99 100644 --- a/buildVars.py +++ b/buildVars.py @@ -31,7 +31,7 @@ pythonSources = [] # Files that contain strings for translation. Usually your python sources -i18nSources = pythonSources + ["buildVars.py"] +i18nSources = pythonSources + ["buildVars.py", "docHandler.py"] # Files that will be ignored when building the nvda-addon file # Paths are relative to the addon directory, not to the root directory of your addon sources. diff --git a/docHandler.py b/docHandler.py index 8aa718b..ccb19b9 100644 --- a/docHandler.py +++ b/docHandler.py @@ -57,7 +57,7 @@ def __init__(self): self.help = gui.mainFrame.sysTrayIcon.helpMenu self.helpItem = self.help.Append(wx.ID_ANY, "{summary} {version}".format(summary=_addonSummary, version=_addonVersion), # Translators: Tooltip for an addon menu item. - _("Open documentation for %s") % _addonName) + _("Opens documentation for %s") % _addonName) gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onHelp, self.helpItem) def onHelp(self, evt): From 465fe8b45a6d683c0d2f88ddc89c4777ab4ef89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 22 Jun 2013 09:02:16 +0200 Subject: [PATCH 039/362] Added style.css and markdown2HTML in features into readme.md. --- README.md | 1 + style.css | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 style.css diff --git a/README.md b/README.md index 237f27b..5034d66 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This template provides the following features you can use to help NVDA add-on de * Compilation of gettext mo files before distribution, when needed. - To generate a gettext pot file, please run scons pot. a **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVar.py is included in i18nFiles. +* Automatic generation of HTML documents from markdown files, to manage documentation in different languages. ## Requirements diff --git a/style.css b/style.css new file mode 100644 index 0000000..373283f --- /dev/null +++ b/style.css @@ -0,0 +1,30 @@ +@charset "utf-8"; +body { +font-family : Verdana, Arial, Helvetica, Sans-serif; +color : #FFFFFF; +background-color : #000000; +line-height: 1.2em; +} +h1, h2 {text-align: center} +dt { +font-weight : bold; +float : left; +width: 10%; +clear: left +} +dd { +margin : 0 0 0.4em 0; +float : left; +width: 90%; +display: block; +} +p { clear : both; +} +a { text-decoration : underline; +} +:active { +text-decoration : none; +} +a:focus, a:hover {outline: solid} +:link {color: #0000FF; +background-color: #FFFFFF} From bc61dd0291a4ceb33e7fcd24c490daa76a0ec11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 22 Jun 2013 09:19:40 +0200 Subject: [PATCH 040/362] Fixed spelling mistake: character capitalization. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5034d66..9ba4de5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This template provides the following features you can use to help NVDA add-on de * Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. * Compilation of gettext mo files before distribution, when needed. -- To generate a gettext pot file, please run scons pot. a **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. +- To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVar.py is included in i18nFiles. * Automatic generation of HTML documents from markdown files, to manage documentation in different languages. From 5502cd9313d657bfebae13be3c02066e2e7f0b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 24 Jun 2013 19:44:17 +0200 Subject: [PATCH 041/362] Minor changes: fixed readme.md. Tabs instead spaces in list items starting with *, so that they can be shown properly. Fixed guidelines to manage documentation. --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9ba4de5..11b2d43 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ This package is distributed under the terms of the GNU General Public License, v ## Features This template provides the following features you can use to help NVDA add-on development: -* Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). -* Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. -* Compilation of gettext mo files before distribution, when needed. +* Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). +* Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. +* Compilation of gettext mo files before distribution, when needed. - To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. -* Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVar.py is included in i18nFiles. -* Automatic generation of HTML documents from markdown files, to manage documentation in different languages. +* Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVar.py is included in i18nFiles. +* Automatic generation of HTML documents from markdown files, to manage documentation in different languages. ## Requirements @@ -39,7 +39,7 @@ You need the following software to use this code for your NVDA add-ons developme ### To manage documentation files for your addon: ### -- Copy the **readme.md** and **docHandler.py** files (contained into addonTemplate) to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. +- Copy the **readme.md** file for your addon, and the **docHandler.py** file, contained into addonTemplate, to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. - Documentation files (named **readme.mdown**) must be placed into addon\doc\/. - Don't use **yourAddonName_docHandler.py** as a name for any file contained in **globalPlugins**; it will be removed to create a menu item for opening your doc addon, under NVDA's help menu. From c6ac35d18f3b38bfa0211cb68271a28446041ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 24 Jun 2013 19:53:41 +0200 Subject: [PATCH 042/362] Now list items of features are rendered properly. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 11b2d43..7976497 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ This package is distributed under the terms of the GNU General Public License, v ## Features This template provides the following features you can use to help NVDA add-on development: + * Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. * Compilation of gettext mo files before distribution, when needed. From a8bdd8ec31a50b12c63b6c650b21d2cc33e18ab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 24 Jun 2013 23:22:55 +0200 Subject: [PATCH 043/362] Added suggestion about lists item. Minor changes: fixed spelling and grammar mistakes. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7976497..6895405 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This template provides the following features you can use to help NVDA add-on de * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. * Compilation of gettext mo files before distribution, when needed. - To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. -* Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVar.py is included in i18nFiles. +* Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. * Automatic generation of HTML documents from markdown files, to manage documentation in different languages. ## Requirements @@ -42,7 +42,9 @@ You need the following software to use this code for your NVDA add-ons developme - Copy the **readme.md** file for your addon, and the **docHandler.py** file, contained into addonTemplate, to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. - Documentation files (named **readme.mdown**) must be placed into addon\doc\/. -- Don't use **yourAddonName_docHandler.py** as a name for any file contained in **globalPlugins**; it will be removed to create a menu item for opening your doc addon, under NVDA's help menu. +- Don't use **yourAddonName_docHandler.py** as a name for any file contained in **globalPlugins**; it will be removed to create a menu item for opening your addon documentation, under NVDA's help menu. + +Note: It's recommended to use hyphens instead of asterisks as tags for lists items, since they provide a better result when converting to HTML. ### To package the add-on for distribution: ### From 2900e6dcb244a31144a08c0b6de1893726dea9f3 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Wed, 26 Jun 2013 11:53:55 +0200 Subject: [PATCH 044/362] * Fix typo * mension addon list * in case of problems, contact addon list, not Rui. renamed: README.md -> readme.md --- README.md => readme.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) rename README.md => readme.md (88%) diff --git a/README.md b/readme.md similarity index 88% rename from README.md rename to readme.md index 6895405..d5e4fe6 100644 --- a/README.md +++ b/readme.md @@ -1,9 +1,10 @@ -# NVDA Add-on Scons Template +# NVDA Add-on Scons Template # This package contains a basic template structure for NVDA add-on development, building, distribution and localization. For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). +The NVDA addon development/discussion list [is here](http://www.freelists.org/list/nvda-addons) -Copyright (C) 2012 - Rui Batista. +Copyright (C) 2012-2013 nvda addon team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. @@ -24,7 +25,7 @@ You need the following software to use this code for your NVDA add-ons developme - a Python distribution (2.7 or greater is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. - Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. -- GNU Gettext tools, if you want to have localization support on your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). +- GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). - Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1). @@ -53,7 +54,4 @@ Note: It's recommended to use hyphens instead of asterisks as tags for lists ite Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. - -## Author Information - -If you have any issues or whatever, please use github, bitbucket, the NVDA development list, or just drop me an email to ruiandrebatista at gmail dot com. +If you have any issues please use the NVDA addon list mensioned above. From 87b079b8cba3b3f7dc21d84e5e0afc728cf8fdcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 1 Jul 2013 05:23:57 +0200 Subject: [PATCH 045/362] utf-8 declared in buildVars.py: now it's possible to use special characters for author names. --- buildVars.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildVars.py b/buildVars.py index f626c99..7a25ef6 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,3 +1,5 @@ +# -*- coding: UTF-8 -*- + # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. From 5cf3e07ee2fb7505ecf467d070d431b0647f0c12 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sun, 7 Jul 2013 13:48:43 +0200 Subject: [PATCH 046/362] * readme files are all expected to be named readme.md * Fixed bug where manifest files were not regenerated when buildVars changed. --- sconstruct | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sconstruct b/sconstruct index c09af93..aa65448 100644 --- a/sconstruct +++ b/sconstruct @@ -41,7 +41,7 @@ def md2html(source, dest): f.write(htmlText) f.write("\n\n") -def mdownTool(env): +def mdTool(env): mdAction=env.Action( lambda target,source,env: md2html(source[0].path, target[0].path), lambda target,source,env: 'Generating %s'%target[0], @@ -49,11 +49,11 @@ def mdownTool(env): mdBuilder=env.Builder( action=mdAction, suffix='.html', - src_suffix='.mdown', + src_suffix='.md', ) env['BUILDERS']['markdown']=mdBuilder -env = Environment(ENV=os.environ, tools=[mdownTool]) +env = Environment(ENV=os.environ, tools=[mdTool]) addonFile = env.File("{addon-name}-{addon-version}.nvda-addon".format(**buildVars.addon_info)) @@ -106,7 +106,7 @@ def createAddonHelp(dir): os.makedirs(docdir) if os.path.isfile("style.css"): shutil.copy("style.css", docdirs[0]) - shutil.copyfile("readme.md", os.path.join(docdir, "readme.mdown")) + shutil.copyfile("readme.md", os.path.join(docdir, "readme.md")) plugindir = os.path.join(dir, "globalPlugins") docFilename = "{addonName}_docHandler.py".format(addonName=buildVars.addon_info["addon-name"]) docPath = os.path.join(plugindir, docFilename) @@ -158,6 +158,7 @@ for dir in langDirs: moFile=env.gettextMoFile(poFile) env.Depends(moFile, poFile) translatedManifest = env.NVDATranslatedManifest(dir.File("manifest.ini"), [moFile, os.path.join("manifest-translated.ini.tpl")]) + env.Depends(translatedManifest, ["buildVars.py"]) env.Depends(addon, [translatedManifest, moFile]) pythonFiles = expandGlobs(buildVars.pythonSources) @@ -166,8 +167,9 @@ for file in pythonFiles: #Convert markdown files to html createAddonHelp("addon") # We need at least doc in English and should append an item to Help menu -for mdownFile in env.Glob(os.path.join('addon', 'doc', '*', '*.mdown')): - htmlFile = env.markdown(mdownFile) +for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): + htmlFile = env.markdown(mdFile) + env.Depends(htmlFile, mdFile) env.Depends(addon, htmlFile) # Pot target From e70513a95d75eabc44c4a4941d91ed570e26beb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 13 Jul 2013 14:01:50 +0200 Subject: [PATCH 047/362] Fixed comment: title for addon summary. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 7a25ef6..ee9250c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -10,7 +10,7 @@ addon_info = { # add-on Name "addon-name" : "addon-template", - # Add-on description + # Add-on summary # TRANSLATORS: Summary for this add-on to be shown on installation and add-on information. "addon-summary" : _("Add-on quick summary"), # Add-on description From 6da9de0dc0b3e0888b7b1966c5d413204de3112f Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Tue, 16 Jul 2013 07:38:33 +0200 Subject: [PATCH 048/362] buildvars.py, cleanup/clarification, also refer to the guidelines for previously unpublished addons. --- buildVars.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/buildVars.py b/buildVars.py index ee9250c..fa9a10a 100644 --- a/buildVars.py +++ b/buildVars.py @@ -8,17 +8,19 @@ # Add-on information variables addon_info = { - # add-on Name - "addon-name" : "addon-template", - # Add-on summary + # for previously unpublished addons, please follow the community guidelines at: + # https://bitbucket.org/nvdaaddonteam/todo guide guideLines.txt + # add-on Name, internal for nvda + "addon-name" : "addonTemplate", + # Add-on summary, usually the user visible name of the addon. # TRANSLATORS: Summary for this add-on to be shown on installation and add-on information. - "addon-summary" : _("Add-on quick summary"), + "addon-summary" : _("Add-on user visible name"), # Add-on description # Translators: Long description to be shown for this add-on on installation and add-on information "addon-description" : _("""Description for the add-on. It can span multiple lines."""), # version - "addon-version" : "x.y.z", + "addon-version" : "x.y", # Author(s) "addon-author" : "name ", # URL for the add-on documentation support From 46929546e5f76fc7721ae5f20fa8d5cba13f474d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 16 Jul 2013 08:47:43 +0200 Subject: [PATCH 049/362] Minor changes in readme. --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index d5e4fe6..920aedf 100644 --- a/readme.md +++ b/readme.md @@ -42,10 +42,10 @@ You need the following software to use this code for your NVDA add-ons developme ### To manage documentation files for your addon: ### - Copy the **readme.md** file for your addon, and the **docHandler.py** file, contained into addonTemplate, to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. -- Documentation files (named **readme.mdown**) must be placed into addon\doc\/. +- Documentation files (named **readme.md**) must be placed into addon\doc\/. - Don't use **yourAddonName_docHandler.py** as a name for any file contained in **globalPlugins**; it will be removed to create a menu item for opening your addon documentation, under NVDA's help menu. -Note: It's recommended to use hyphens instead of asterisks as tags for lists items, since they provide a better result when converting to HTML. +Note: It's recommended to use hyphens instead of asterisks as tags for lists items, since they provide a better result when converting to HTML. You can also use asterisks followed by tab. ### To package the add-on for distribution: ### From e05a4156659d06d4a6507a0ea039e3edb8d78778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 16 Jul 2013 09:00:25 +0200 Subject: [PATCH 050/362] Fixed revious dead link to guidelines. Fixed description comment as description is not shown on installation. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index fa9a10a..c6bbbce 100644 --- a/buildVars.py +++ b/buildVars.py @@ -9,7 +9,7 @@ # Add-on information variables addon_info = { # for previously unpublished addons, please follow the community guidelines at: - # https://bitbucket.org/nvdaaddonteam/todo guide guideLines.txt + # https://bitbucket.org/nvdaaddonteam/todo/src/56140dbec531e4d7591338e1dbc6192f3dd422a8/guideLines.txt # add-on Name, internal for nvda "addon-name" : "addonTemplate", # Add-on summary, usually the user visible name of the addon. From 06fa928c762b70e8b9134a44fb8124cd65098c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 16 Jul 2013 10:38:58 +0200 Subject: [PATCH 051/362] Now fixed comment for description, dismissed in previous commit. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index c6bbbce..477867d 100644 --- a/buildVars.py +++ b/buildVars.py @@ -16,7 +16,7 @@ # TRANSLATORS: Summary for this add-on to be shown on installation and add-on information. "addon-summary" : _("Add-on user visible name"), # Add-on description - # Translators: Long description to be shown for this add-on on installation and add-on information + # Translators: Long description to be shown for this add-on on add-on information from add-ons manager "addon-description" : _("""Description for the add-on. It can span multiple lines."""), # version From 4667802d5c7f96e235b34dc779cc53057ceb5a44 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 18 Jul 2013 11:06:17 -0700 Subject: [PATCH 052/362] Readme - clarified the extension of the markdown file. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 920aedf..f8e1028 100644 --- a/readme.md +++ b/readme.md @@ -17,7 +17,7 @@ This template provides the following features you can use to help NVDA add-on de * Compilation of gettext mo files before distribution, when needed. - To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. -* Automatic generation of HTML documents from markdown files, to manage documentation in different languages. +* Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. ## Requirements From c6cab9e072a0c8ef00792de4bf0a6b77c3b78fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Wed, 31 Jul 2013 18:09:00 +0200 Subject: [PATCH 053/362] Removed translatable strings of docHandler: the tooltip of the menu item is just the corresponding addon name. --- docHandler.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docHandler.py b/docHandler.py index ccb19b9..8dde60e 100644 --- a/docHandler.py +++ b/docHandler.py @@ -55,9 +55,7 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin): def __init__(self): super(globalPluginHandler.GlobalPlugin, self).__init__() self.help = gui.mainFrame.sysTrayIcon.helpMenu - self.helpItem = self.help.Append(wx.ID_ANY, "{summary} {version}".format(summary=_addonSummary, version=_addonVersion), - # Translators: Tooltip for an addon menu item. - _("Opens documentation for %s") % _addonName) + self.helpItem = self.help.Append(wx.ID_ANY, "{summary} {version}".format(summary=_addonSummary, version=_addonVersion), _addonName) gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onHelp, self.helpItem) def onHelp(self, evt): From 07c454b288669597933c1348cba00ead0691762b Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Thu, 15 Aug 2013 19:59:08 +0100 Subject: [PATCH 054/362] If docHandler.py is not present, don't copy README.md to the addon/doc/en folder, since it won't be used by defaulti. Alos lazily import markdown on HTML generation, if we don't have markdown files in the add-on the module is not needed on the system that is compiling it. --- sconstruct | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index aa65448..eb7caae 100644 --- a/sconstruct +++ b/sconstruct @@ -9,13 +9,13 @@ import shutil import os import os.path import zipfile -import markdown import configobj import buildVars def md2html(source, dest): + import markdown lang = os.path.basename(os.path.dirname(source)).replace('_', '-') title="{addonSummary} {addonVersion}".format(addonSummary=buildVars.addon_info["addon-summary"], addonVersion=buildVars.addon_info["addon-version"]) headerDic = { @@ -98,8 +98,9 @@ env['BUILDERS']['gettextMergePotFile']=env.Builder( suffix=".pot") def createAddonHelp(dir): - if not os.path.isfile("readme.md") or not os.path.isfile("docHandler.py"): + if not os.path.isfile("docHandler.py"): return + assert os.path.isfile("readme.md") docdirs = [os.path.join(dir, "doc"), os.path.join(dir, "doc", "en")] for docdir in docdirs: if not os.path.isdir(docdir): From d38c03ccaa7422d056328e8bbd1645835adb0824 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Fri, 16 Aug 2013 18:53:48 +0100 Subject: [PATCH 055/362] Use scons copy action instead of shutil.copyfile when creating add-on help so cleanning and target dependencies work as expected. --- sconstruct | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/sconstruct b/sconstruct index eb7caae..b958b1d 100644 --- a/sconstruct +++ b/sconstruct @@ -5,7 +5,6 @@ import codecs import gettext -import shutil import os import os.path import zipfile @@ -100,20 +99,22 @@ env['BUILDERS']['gettextMergePotFile']=env.Builder( def createAddonHelp(dir): if not os.path.isfile("docHandler.py"): return - assert os.path.isfile("readme.md") - docdirs = [os.path.join(dir, "doc"), os.path.join(dir, "doc", "en")] - for docdir in docdirs: - if not os.path.isdir(docdir): - os.makedirs(docdir) - if os.path.isfile("style.css"): - shutil.copy("style.css", docdirs[0]) - shutil.copyfile("readme.md", os.path.join(docdir, "readme.md")) plugindir = os.path.join(dir, "globalPlugins") docFilename = "{addonName}_docHandler.py".format(addonName=buildVars.addon_info["addon-name"]) docPath = os.path.join(plugindir, docFilename) - if not os.path.isdir(plugindir): - os.makedirs(plugindir) - shutil.copyfile("docHandler.py", docPath) + docFileTarget = env.Command(docPath, "docHandler.py", Copy("$TARGET", "$SOURCE")) + env.Depends(addon, docFileTarget) + docsDir = os.path.join(dir, "doc") + if os.path.isfile("style.css"): + cssPath = os.path.join(docsDir, "style.css") + cssTarget = env.Command(cssPath, "style.css", Copy("$TARGET", "$SOURCE")) + env.Depends(docFileTarget, cssTarget) + if os.path.isfile("README.md"): + readmePath = os.path.join(docsDir, "en", "README.md") + readmeTarget = env.Command(readmePath, "README.md", Copy("$TARGET", "$SOURCE")) + env.Depends(docFileTarget, readmeTarget) + + def createAddonBundleFromPath(path, dest): """ Creates a bundle from a directory that contains an addon manifest file.""" From 6cc9d67cd9becbf81db04d3b5061a991840b14be Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sat, 17 Aug 2013 17:09:12 +0100 Subject: [PATCH 056/362] Copy of docHandler.py should not depend on copy of english README and css to doc folder. This makes scons also compute most dependencies by itself. --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index b958b1d..9754cf5 100644 --- a/sconstruct +++ b/sconstruct @@ -108,11 +108,11 @@ def createAddonHelp(dir): if os.path.isfile("style.css"): cssPath = os.path.join(docsDir, "style.css") cssTarget = env.Command(cssPath, "style.css", Copy("$TARGET", "$SOURCE")) - env.Depends(docFileTarget, cssTarget) + env.Depends(addon, cssTarget) if os.path.isfile("README.md"): readmePath = os.path.join(docsDir, "en", "README.md") readmeTarget = env.Command(readmePath, "README.md", Copy("$TARGET", "$SOURCE")) - env.Depends(docFileTarget, readmeTarget) + env.Depends(addon, readmeTarget) From edfce095642727c945a60d7766b9f35ee7c8b9a2 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sun, 18 Aug 2013 19:07:24 +0100 Subject: [PATCH 057/362] Use unicode string when creating help menu item in docHandler. --- docHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docHandler.py b/docHandler.py index 8dde60e..c142e42 100644 --- a/docHandler.py +++ b/docHandler.py @@ -55,7 +55,7 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin): def __init__(self): super(globalPluginHandler.GlobalPlugin, self).__init__() self.help = gui.mainFrame.sysTrayIcon.helpMenu - self.helpItem = self.help.Append(wx.ID_ANY, "{summary} {version}".format(summary=_addonSummary, version=_addonVersion), _addonName) + self.helpItem = self.help.Append(wx.ID_ANY, u"{summary} {version}".format(summary=_addonSummary, version=_addonVersion), _addonName) gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onHelp, self.helpItem) def onHelp(self, evt): From a77ea48bfb4befc6d11c059d395479fcb9332ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Wed, 9 Oct 2013 05:24:22 +0200 Subject: [PATCH 058/362] Fixed URL for updated guidelines. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 477867d..69d8cb5 100644 --- a/buildVars.py +++ b/buildVars.py @@ -9,7 +9,7 @@ # Add-on information variables addon_info = { # for previously unpublished addons, please follow the community guidelines at: - # https://bitbucket.org/nvdaaddonteam/todo/src/56140dbec531e4d7591338e1dbc6192f3dd422a8/guideLines.txt + # https://bitbucket.org/nvdaaddonteam/todo/src/37bd08d42c17e72ae303fee4a60821ea0c2f4c5a/guideLines.txt?at=master # add-on Name, internal for nvda "addon-name" : "addonTemplate", # Add-on summary, usually the user visible name of the addon. From dd593f6fe4687cfc1a70c363174b0681b46959d8 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Sat, 12 Oct 2013 15:20:05 +0200 Subject: [PATCH 059/362] another fix for guidelines url, hopefully this should be a stable url now. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 69d8cb5..b0af259 100644 --- a/buildVars.py +++ b/buildVars.py @@ -9,7 +9,7 @@ # Add-on information variables addon_info = { # for previously unpublished addons, please follow the community guidelines at: - # https://bitbucket.org/nvdaaddonteam/todo/src/37bd08d42c17e72ae303fee4a60821ea0c2f4c5a/guideLines.txt?at=master + # https://bitbucket.org/nvdaaddonteam/todo/raw/master/guideLines.txt # add-on Name, internal for nvda "addon-name" : "addonTemplate", # Add-on summary, usually the user visible name of the addon. From 699a48c9cfecd41be47fc951542611fbacbc139f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 21 Oct 2013 22:49:54 +0200 Subject: [PATCH 060/362] sconstruct: readme is lowercase when copied to doc folder. --- sconstruct | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index 9754cf5..1d54d6e 100644 --- a/sconstruct +++ b/sconstruct @@ -109,9 +109,9 @@ def createAddonHelp(dir): cssPath = os.path.join(docsDir, "style.css") cssTarget = env.Command(cssPath, "style.css", Copy("$TARGET", "$SOURCE")) env.Depends(addon, cssTarget) - if os.path.isfile("README.md"): - readmePath = os.path.join(docsDir, "en", "README.md") - readmeTarget = env.Command(readmePath, "README.md", Copy("$TARGET", "$SOURCE")) + if os.path.isfile("readme.md"): + readmePath = os.path.join(docsDir, "en", "readme.md") + readmeTarget = env.Command(readmePath, "readme.md", Copy("$TARGET", "$SOURCE")) env.Depends(addon, readmeTarget) From 7eac4d710526047811baf62e6213f74cc5f492d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 21 Oct 2013 22:51:40 +0200 Subject: [PATCH 061/362] buildVars.py: fixed capitalization in comment for translators. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index b0af259..e9af258 100644 --- a/buildVars.py +++ b/buildVars.py @@ -13,7 +13,7 @@ # add-on Name, internal for nvda "addon-name" : "addonTemplate", # Add-on summary, usually the user visible name of the addon. - # TRANSLATORS: Summary for this add-on to be shown on installation and add-on information. + # Translators: Summary for this add-on to be shown on installation and add-on information. "addon-summary" : _("Add-on user visible name"), # Add-on description # Translators: Long description to be shown for this add-on on add-on information from add-ons manager From da711a136090ea7721890118f89416f245bcfffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 21 Oct 2013 22:54:09 +0200 Subject: [PATCH 062/362] Fixed bug; buildVars.py: used unicode in author field, as certain characters cannot be recognized when building the add-ons. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index e9af258..edde875 100644 --- a/buildVars.py +++ b/buildVars.py @@ -22,7 +22,7 @@ # version "addon-version" : "x.y", # Author(s) - "addon-author" : "name ", + "addon-author" : u"name ", # URL for the add-on documentation support "addon-url" : None } From 08e39fb5e65312e8546f4cf15fce2b9fa1043dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Wed, 30 Oct 2013 07:04:29 +0100 Subject: [PATCH 063/362] updated docHandler:now non-latin characters are supported in the root of add-ons. --- docHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docHandler.py b/docHandler.py index c142e42..b514fe4 100644 --- a/docHandler.py +++ b/docHandler.py @@ -12,7 +12,7 @@ addonHandler.initTranslation() -_addonDir = os.path.join(os.path.dirname(__file__), "..") # The root of an addon folder +_addonDir = os.path.join(os.path.dirname(__file__), "..").decode("mbcs") # The root of an addon folder _docFileName = "readme.html" # The name of an addon documentation file _curAddon = addonHandler.Addon(_addonDir) # Addon instance _addonSummary = _curAddon.manifest['summary'] From b916592d394b1982a05891b8f647330ad554185d Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Thu, 14 Nov 2013 09:53:16 +0100 Subject: [PATCH 064/362] updated .gitattributes, for better po file handling. For po files, set a cleanpo filter. Also include url so that the personal config can be changed to include the cleanpo. --- .gitattributes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitattributes b/.gitattributes index ceae4de..a1a1316 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,8 @@ # Set default behaviour, in case users don't have core.autocrlf set. * text=auto + +# Try to ensure that po files in the repo does not include +# source code line numbers. +# Every person expected to commit po files should change their personal config file as described here: +# https://mail.gnome.org/archives/kupfer-list/2010-June/msg00002.html +*.po filter=cleanpo From 74d93e49d856ceabadfcf229f5b9d5272df058bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 10 Dec 2013 21:38:14 +0100 Subject: [PATCH 065/362] Removed recommendation about using hyphens for creating lists in documentation, since they seem not to work in po conversion. --- readme.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/readme.md b/readme.md index f8e1028..ea509fe 100644 --- a/readme.md +++ b/readme.md @@ -45,8 +45,6 @@ You need the following software to use this code for your NVDA add-ons developme - Documentation files (named **readme.md**) must be placed into addon\doc\/. - Don't use **yourAddonName_docHandler.py** as a name for any file contained in **globalPlugins**; it will be removed to create a menu item for opening your addon documentation, under NVDA's help menu. -Note: It's recommended to use hyphens instead of asterisks as tags for lists items, since they provide a better result when converting to HTML. You can also use asterisks followed by tab. - ### To package the add-on for distribution: ### - Open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. From 6838999e15dae35fdc677c8c5445e5169940bbaf Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 19 Dec 2013 18:50:15 -0800 Subject: [PATCH 066/362] Added the actual addon folder structure with required subfolders for module types. Because Git does not allow empty directories in repos, a readme.txt has been included in these folders. Add-on writers should not include these files in add-on code. --- addon/appModules/readme.txt | 2 ++ addon/brailleDisplayDrivers/readme.txt | 2 ++ addon/globalPlugins/readme.txt | 2 ++ addon/synthDrivers/readme.txt | 2 ++ readme.md | 4 ++-- 5 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 addon/appModules/readme.txt create mode 100644 addon/brailleDisplayDrivers/readme.txt create mode 100644 addon/globalPlugins/readme.txt create mode 100644 addon/synthDrivers/readme.txt diff --git a/addon/appModules/readme.txt b/addon/appModules/readme.txt new file mode 100644 index 0000000..1acc9d0 --- /dev/null +++ b/addon/appModules/readme.txt @@ -0,0 +1,2 @@ +# app modules directory. +# Code related to app modules should go in this folder. diff --git a/addon/brailleDisplayDrivers/readme.txt b/addon/brailleDisplayDrivers/readme.txt new file mode 100644 index 0000000..561ce87 --- /dev/null +++ b/addon/brailleDisplayDrivers/readme.txt @@ -0,0 +1,2 @@ +# Braille display drivers directory. +# Code related to braille display support should go in this folder. diff --git a/addon/globalPlugins/readme.txt b/addon/globalPlugins/readme.txt new file mode 100644 index 0000000..66a00aa --- /dev/null +++ b/addon/globalPlugins/readme.txt @@ -0,0 +1,2 @@ +# Global plugins directory. +# Code related to global plugins should go in this folder. diff --git a/addon/synthDrivers/readme.txt b/addon/synthDrivers/readme.txt new file mode 100644 index 0000000..d6561b1 --- /dev/null +++ b/addon/synthDrivers/readme.txt @@ -0,0 +1,2 @@ +# Synth drivers directory. +# Code related to synthesizer support should go in this folder. diff --git a/readme.md b/readme.md index ea509fe..d202353 100644 --- a/readme.md +++ b/readme.md @@ -36,7 +36,7 @@ You need the following software to use this code for your NVDA add-ons developme - Create an empty folder to hold the files for your add-on. - Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, .gitignore and .gitattributes files to the created folder. - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). -- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. +- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. Be sure to not include the readme.txt file inside these subfolders in your add-on. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. ### To manage documentation files for your addon: ### @@ -47,7 +47,7 @@ You need the following software to use this code for your NVDA add-ons developme ### To package the add-on for distribution: ### -- Open a command line, change to the folder that has the **SCONSTRUCT** file and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. +- Open a command line, change to the folder that has the **SCONSTRUCT** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. - You can further customize variables in the **buildVars.py** file. Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From 274d3b3d61fc0bd8f965f3a74f6e5f154de840ff Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 22 Dec 2013 07:24:37 -0800 Subject: [PATCH 067/362] Add-on template readme: add-ons require ConfigObj to be installed in order to build. --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index d202353..0c23e7f 100644 --- a/readme.md +++ b/readme.md @@ -27,6 +27,7 @@ You need the following software to use this code for your NVDA add-ons developme - Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. - GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). - Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1). +- ConfigObj 4.6.2 or later to store add-on settings. You can grab the latest version here: [ConfigObj latest download](https://pypi.python.org/pypi/configobj/). ## Usage From 3c7db7696dfbaa4de5cdc607416ccfaf1ea63236 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 22 Dec 2013 07:30:23 -0800 Subject: [PATCH 068/362] Template: remolved addon folder; readme: modified to note that the add-on writer needs to create addon folder and needed module subfolders. --- addon/appModules/readme.txt | 2 -- addon/brailleDisplayDrivers/readme.txt | 2 -- addon/globalPlugins/readme.txt | 2 -- addon/synthDrivers/readme.txt | 2 -- readme.md | 5 +++-- 5 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 addon/appModules/readme.txt delete mode 100644 addon/brailleDisplayDrivers/readme.txt delete mode 100644 addon/globalPlugins/readme.txt delete mode 100644 addon/synthDrivers/readme.txt diff --git a/addon/appModules/readme.txt b/addon/appModules/readme.txt deleted file mode 100644 index 1acc9d0..0000000 --- a/addon/appModules/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -# app modules directory. -# Code related to app modules should go in this folder. diff --git a/addon/brailleDisplayDrivers/readme.txt b/addon/brailleDisplayDrivers/readme.txt deleted file mode 100644 index 561ce87..0000000 --- a/addon/brailleDisplayDrivers/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Braille display drivers directory. -# Code related to braille display support should go in this folder. diff --git a/addon/globalPlugins/readme.txt b/addon/globalPlugins/readme.txt deleted file mode 100644 index 66a00aa..0000000 --- a/addon/globalPlugins/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Global plugins directory. -# Code related to global plugins should go in this folder. diff --git a/addon/synthDrivers/readme.txt b/addon/synthDrivers/readme.txt deleted file mode 100644 index d6561b1..0000000 --- a/addon/synthDrivers/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Synth drivers directory. -# Code related to synthesizer support should go in this folder. diff --git a/readme.md b/readme.md index 0c23e7f..3f94045 100644 --- a/readme.md +++ b/readme.md @@ -35,9 +35,10 @@ You need the following software to use this code for your NVDA add-ons developme ### To create a new NVDA add-on, taking advantage of this template: ### - Create an empty folder to hold the files for your add-on. -- Copy the **addon** folder, the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, .gitignore and .gitattributes files to the created folder. +- Create an **addon** folder inside this new folder. Inside **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. +- Copy the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, .gitignore and .gitattributes files to the created folder. - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). -- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. You can delete folders you don't need for your particular add-on package. Be sure to not include the readme.txt file inside these subfolders in your add-on. +- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. ### To manage documentation files for your addon: ### From 874884080b31c17a5473d2cb09da805168582fd5 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sun, 6 Jul 2014 20:46:03 +0100 Subject: [PATCH 069/362] Removed docHandler dummy plugin, documentation is now handled in the add-ons manager (see ticket #2694) --- docHandler.py | 68 ------------------------------------------------ manifest.ini.tpl | 1 + sconstruct | 7 ----- 3 files changed, 1 insertion(+), 75 deletions(-) delete mode 100644 docHandler.py diff --git a/docHandler.py b/docHandler.py deleted file mode 100644 index b514fe4..0000000 --- a/docHandler.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: UTF-8 -*- - -# docHandler: module for managing addons documentation -# See: http://community.nvda-project.org/ticket/2694 - -import os -import languageHandler -import addonHandler -import globalPluginHandler -import gui -import wx - -addonHandler.initTranslation() - -_addonDir = os.path.join(os.path.dirname(__file__), "..").decode("mbcs") # The root of an addon folder -_docFileName = "readme.html" # The name of an addon documentation file -_curAddon = addonHandler.Addon(_addonDir) # Addon instance -_addonSummary = _curAddon.manifest['summary'] -_addonVersion = _curAddon.manifest['version'] -_addonName = _curAddon.manifest['name'] - -def getDocFolder(addonDir=_addonDir): - langs = [languageHandler.getLanguage(), "en"] - for lang in langs: - docFolder = os.path.join(addonDir, "doc", lang) - if os.path.isdir(docFolder): - return docFolder - if "_" in lang: - tryLang = lang.split("_")[0] - docFolder = os.path.join(addonDir, "doc", tryLang) - if os.path.isdir(docFolder): - return docFolder - if tryLang == "en": - break - if lang == "en": - break - return None - -def getDocPath(docFileName=_docFileName): - docPath = getDocFolder() - if docPath is not None: - docFile = os.path.join(docPath, docFileName) - if os.path.isfile(docFile): - docPath = docFile - return docPath - -def openDocPath(): - try: - os.startfile(getDocPath()) - except WindowsError: - pass - -class GlobalPlugin(globalPluginHandler.GlobalPlugin): - - def __init__(self): - super(globalPluginHandler.GlobalPlugin, self).__init__() - self.help = gui.mainFrame.sysTrayIcon.helpMenu - self.helpItem = self.help.Append(wx.ID_ANY, u"{summary} {version}".format(summary=_addonSummary, version=_addonVersion), _addonName) - gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onHelp, self.helpItem) - - def onHelp(self, evt): - openDocPath() - - def terminate(self): - try: - self.help.RemoveItem(self.helpItem) - except wx.PyDeadObjectError: - pass diff --git a/manifest.ini.tpl b/manifest.ini.tpl index 8093a3f..39658e8 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -4,3 +4,4 @@ description = """{addon-description}""" author = "{addon-author}" url = {addon-url} version = {addon-version} +docFileName = readme.html \ No newline at end of file diff --git a/sconstruct b/sconstruct index 1d54d6e..e0c0e31 100644 --- a/sconstruct +++ b/sconstruct @@ -97,13 +97,6 @@ env['BUILDERS']['gettextMergePotFile']=env.Builder( suffix=".pot") def createAddonHelp(dir): - if not os.path.isfile("docHandler.py"): - return - plugindir = os.path.join(dir, "globalPlugins") - docFilename = "{addonName}_docHandler.py".format(addonName=buildVars.addon_info["addon-name"]) - docPath = os.path.join(plugindir, docFilename) - docFileTarget = env.Command(docPath, "docHandler.py", Copy("$TARGET", "$SOURCE")) - env.Depends(addon, docFileTarget) docsDir = os.path.join(dir, "doc") if os.path.isfile("style.css"): cssPath = os.path.join(docsDir, "style.css") From 623bedf6219bc2d25523bdd4b7fbc0d7d2962453 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Mon, 7 Jul 2014 12:46:32 +0100 Subject: [PATCH 070/362] Refactoe gettext into an independent module. --- sconstruct | 25 ++++------------ site_scons/site_tools/gettexttool.py | 44 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 site_scons/site_tools/gettexttool.py diff --git a/sconstruct b/sconstruct index e0c0e31..462aa3f 100644 --- a/sconstruct +++ b/sconstruct @@ -4,7 +4,6 @@ #See the file COPYING.txt for more details. import codecs -import gettext import os import os.path import zipfile @@ -52,7 +51,12 @@ def mdTool(env): ) env['BUILDERS']['markdown']=mdBuilder -env = Environment(ENV=os.environ, tools=[mdTool]) +env = Environment(ENV=os.environ, tools=['gettexttool', mdTool], + gettextvars={ + 'package-bugs-address' : 'nvda-translations@freelists.org', + 'package-name' : buildVars.addon_info['addon-name'], + 'package-version' : buildVars.addon_info['addon-version'] + }) addonFile = env.File("{addon-name}-{addon-version}.nvda-addon".format(**buildVars.addon_info)) @@ -79,23 +83,6 @@ env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) env['BUILDERS']['NVDAManifest'] = Builder(generator=manifestGenerator) env['BUILDERS']['NVDATranslatedManifest'] = Builder(generator=translatedManifestGenerator) -env['BUILDERS']['gettextMoFile']=env.Builder( - action=env.Action(["msgfmt -o $TARGETS $SOURCES"], lambda t, s, e : "Compiling translation %s" % s[0]), - suffix=".mo", - src_suffix=".po" -) - -env['BUILDERS']['gettextPotFile']=env.Builder( - action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' -c -o $TARGETS $SOURCES" % - ("nvda-translations@freelists.org", buildVars.addon_info['addon-name'], buildVars.addon_info['addon-version']) - ], lambda t, s, e : "Generating pot file %s" % t[0]), - suffix=".pot") -env['BUILDERS']['gettextMergePotFile']=env.Builder( - action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' --omit-header --no-location -c -o $TARGETS $SOURCES" % - ("nvda-translations@freelists.org", buildVars.addon_info['addon-name'], buildVars.addon_info['addon-version']) - ], lambda t, s, e : "Generating pot file %s" % t[0]), - suffix=".pot") - def createAddonHelp(dir): docsDir = os.path.join(dir, "doc") if os.path.isfile("style.css"): diff --git a/site_scons/site_tools/gettexttool.py b/site_scons/site_tools/gettexttool.py new file mode 100644 index 0000000..c683fe2 --- /dev/null +++ b/site_scons/site_tools/gettexttool.py @@ -0,0 +1,44 @@ +""" This tool allows generation of gettext .mo compiled files, pot files from source code files +and pot files for merging. + +Three new builders are added into the constructed environment: + +- gettextMoFile: generates .mo file from .pot file using msgfmt. +- gettextPotFile: Generates .pot file from source code files. +- gettextMergePotFile: Creates a .pot file appropriate for merging into existing .po files. + +To properly configure gettext, pass a `gettextvars* dictionary on environment construction with the following keys: + +- package-bugs-address +- package-name +- package-version +""" + + +def exists(env): + return True + +def generate(env): + env.SetDefault(gettextvars={ + "package-bugs-address" : "", + "package-name" : "", + "package-version" : "" + }) + + env['BUILDERS']['gettextMoFile']=env.Builder( + action=env.Action(["msgfmt -o $TARGETS $SOURCES"], lambda t, s, e : "Compiling translation %s" % s[0]), + suffix=".mo", + src_suffix=".po" + ) + + env['BUILDERS']['gettextPotFile']=env.Builder( + action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' -c -o $TARGETS $SOURCES" % + (env['gettextvars']['package-bugs-address'], env['gettextvars']['package-name'], env['gettextvars']['package-version']) + ], lambda t, s, e : "Generating pot file %s" % t[0]), + suffix=".pot") + + env['BUILDERS']['gettextMergePotFile']=env.Builder( + action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' --omit-header --no-location -c -o $TARGETS $SOURCES" % + (env['gettextvars']['package-bugs-address'], env['gettextvars']['package-name'], env['gettextvars']['package-version'])], lambda t, s, e : "Generating pot file %s" % t[0]), + suffix=".pot") + From 9608f8cbd0ed0b418f3aff8fb132c5cbb32cce06 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Mon, 7 Jul 2014 15:37:15 +0100 Subject: [PATCH 071/362] Make gettext variables apear as top construction variables and much simplify gettext tool by taking advantage of variable interpolation. --- sconstruct | 15 ++++++++------- site_scons/site_tools/gettexttool.py | 27 +++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/sconstruct b/sconstruct index 462aa3f..1c35754 100644 --- a/sconstruct +++ b/sconstruct @@ -1,5 +1,5 @@ # NVDA add-on template SCONSTRUCT file -#Copyright (C) 2012 Rui Batista +#Copyright (C) 2012, 2014 Rui Batista #This file is covered by the GNU General Public License. #See the file COPYING.txt for more details. @@ -51,12 +51,13 @@ def mdTool(env): ) env['BUILDERS']['markdown']=mdBuilder -env = Environment(ENV=os.environ, tools=['gettexttool', mdTool], - gettextvars={ - 'package-bugs-address' : 'nvda-translations@freelists.org', - 'package-name' : buildVars.addon_info['addon-name'], - 'package-version' : buildVars.addon_info['addon-version'] - }) + +gettextvars={ + 'gettext_package_bugs_address' : 'nvda-translations@freelists.org', + 'gettext_package_name' : buildVars.addon_info['addon-name'], + 'gettext_package_version' : buildVars.addon_info['addon-version'] + } +env = Environment(ENV=os.environ, tools=['gettexttool', mdTool], **gettextvars) addonFile = env.File("{addon-name}-{addon-version}.nvda-addon".format(**buildVars.addon_info)) diff --git a/site_scons/site_tools/gettexttool.py b/site_scons/site_tools/gettexttool.py index c683fe2..6eaaa7f 100644 --- a/site_scons/site_tools/gettexttool.py +++ b/site_scons/site_tools/gettexttool.py @@ -7,11 +7,13 @@ - gettextPotFile: Generates .pot file from source code files. - gettextMergePotFile: Creates a .pot file appropriate for merging into existing .po files. -To properly configure gettext, pass a `gettextvars* dictionary on environment construction with the following keys: +To properly configure get text, define the following variables: + +- gettext_package_bugs_address +- gettext_package_name +- gettext_package_version + -- package-bugs-address -- package-name -- package-version """ @@ -19,11 +21,9 @@ def exists(env): return True def generate(env): - env.SetDefault(gettextvars={ - "package-bugs-address" : "", - "package-name" : "", - "package-version" : "" - }) + env.SetDefault(gettext_package_bugs_address="example@example.com") + env.SetDefault(gettext_package_name="") + env.SetDefault(gettext_package_version="") env['BUILDERS']['gettextMoFile']=env.Builder( action=env.Action(["msgfmt -o $TARGETS $SOURCES"], lambda t, s, e : "Compiling translation %s" % s[0]), @@ -32,13 +32,12 @@ def generate(env): ) env['BUILDERS']['gettextPotFile']=env.Builder( - action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' -c -o $TARGETS $SOURCES" % - (env['gettextvars']['package-bugs-address'], env['gettextvars']['package-name'], env['gettextvars']['package-version']) - ], lambda t, s, e : "Generating pot file %s" % t[0]), + action=env.Action(["xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-version='$gettext_package_version' -c -o $TARGETS $SOURCES"], + lambda t, s, e : "Generating pot file %s" % t[0]), suffix=".pot") env['BUILDERS']['gettextMergePotFile']=env.Builder( - action=env.Action(["xgettext --msgid-bugs-address='%s' --package-name='%s' --package-version='%s' --omit-header --no-location -c -o $TARGETS $SOURCES" % - (env['gettextvars']['package-bugs-address'], env['gettextvars']['package-name'], env['gettextvars']['package-version'])], lambda t, s, e : "Generating pot file %s" % t[0]), + action=env.Action(["xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-version='$gettext_package_version' --omit-header --no-location -c -o $TARGETS $SOURCES"], + lambda t, s, e : "Generating pot file %s" % t[0]), suffix=".pot") From a6005be4f34ad48b85cb3b878c4ae0c97cf10b8a Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sun, 13 Jul 2014 17:48:19 +0100 Subject: [PATCH 072/362] Simplify gettext tool with more variable interpolation. --- site_scons/site_tools/gettexttool.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/site_scons/site_tools/gettexttool.py b/site_scons/site_tools/gettexttool.py index 6eaaa7f..97fd629 100644 --- a/site_scons/site_tools/gettexttool.py +++ b/site_scons/site_tools/gettexttool.py @@ -15,7 +15,7 @@ """ - +from SCons.Action import Action def exists(env): return True @@ -26,18 +26,18 @@ def generate(env): env.SetDefault(gettext_package_version="") env['BUILDERS']['gettextMoFile']=env.Builder( - action=env.Action(["msgfmt -o $TARGETS $SOURCES"], lambda t, s, e : "Compiling translation %s" % s[0]), + action=Action("msgfmt -o $TARGET $SOURCE", "Compiling translation $SOURCE"), suffix=".mo", src_suffix=".po" ) env['BUILDERS']['gettextPotFile']=env.Builder( - action=env.Action(["xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-version='$gettext_package_version' -c -o $TARGETS $SOURCES"], - lambda t, s, e : "Generating pot file %s" % t[0]), + action=Action("xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-version='$gettext_package_version' -c -o $TARGET $SOURCE", + "Generating pot file $TARGET"), suffix=".pot") env['BUILDERS']['gettextMergePotFile']=env.Builder( - action=env.Action(["xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-version='$gettext_package_version' --omit-header --no-location -c -o $TARGETS $SOURCES"], - lambda t, s, e : "Generating pot file %s" % t[0]), + action=Action("xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-ve rsion='$gettext_package_version' --omit-header --no-location -c -o $TARGET $OURCES", + "Generating pot file %TARGET"), suffix=".pot") From e3bccede6a11ebe670024ac6e903635ac90c0601 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Sun, 13 Jul 2014 17:50:43 +0100 Subject: [PATCH 073/362] Import gettext, we still need for manifest generation. --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 1c35754..f2d91b6 100644 --- a/sconstruct +++ b/sconstruct @@ -4,10 +4,10 @@ #See the file COPYING.txt for more details. import codecs +import gettext import os import os.path import zipfile -import configobj import buildVars From 254beb19910cafedc12e2eb92ae69c80c808aae0 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Mon, 14 Jul 2014 16:07:13 +0100 Subject: [PATCH 074/362] Make gettext tool a package. --- site_scons/site_tools/{gettexttool.py => gettexttool/__init__.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename site_scons/site_tools/{gettexttool.py => gettexttool/__init__.py} (100%) diff --git a/site_scons/site_tools/gettexttool.py b/site_scons/site_tools/gettexttool/__init__.py similarity index 100% rename from site_scons/site_tools/gettexttool.py rename to site_scons/site_tools/gettexttool/__init__.py From f725d4ed6a2cddc2d568d303e8f632824daa27f2 Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Tue, 15 Jul 2014 16:14:42 +0100 Subject: [PATCH 075/362] Use scons environment variable interpulation to simplify most code. --- buildVars.py | 14 ++++++++------ manifest-translated.ini.tpl | 4 ++-- manifest.ini.tpl | 14 +++++++------- sconstruct | 25 +++++++++++++------------ 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/buildVars.py b/buildVars.py index edde875..5af17b0 100644 --- a/buildVars.py +++ b/buildVars.py @@ -11,20 +11,22 @@ # for previously unpublished addons, please follow the community guidelines at: # https://bitbucket.org/nvdaaddonteam/todo/raw/master/guideLines.txt # add-on Name, internal for nvda - "addon-name" : "addonTemplate", + "addon_name" : "addonTemplate", # Add-on summary, usually the user visible name of the addon. # Translators: Summary for this add-on to be shown on installation and add-on information. - "addon-summary" : _("Add-on user visible name"), + "addon_summary" : _("Add-on user visible name"), # Add-on description # Translators: Long description to be shown for this add-on on add-on information from add-ons manager - "addon-description" : _("""Description for the add-on. + "addon_description" : _("""Description for the add-on. It can span multiple lines."""), # version - "addon-version" : "x.y", + "addon_version" : "x.y", # Author(s) - "addon-author" : u"name ", + "addon_author" : u"name ", # URL for the add-on documentation support - "addon-url" : None + "addon_url" : None, + # Documentation file name + "addon_docFileName" : "readme.html", } diff --git a/manifest-translated.ini.tpl b/manifest-translated.ini.tpl index 4750635..c06aa84 100644 --- a/manifest-translated.ini.tpl +++ b/manifest-translated.ini.tpl @@ -1,2 +1,2 @@ -summary = "{addon-summary}" -description = """{addon-description}""" +summary = "{addon_summary}" +description = """{addon_description}""" diff --git a/manifest.ini.tpl b/manifest.ini.tpl index 39658e8..7de43bf 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -1,7 +1,7 @@ -name = {addon-name} -summary = "{addon-summary}" -description = """{addon-description}""" -author = "{addon-author}" -url = {addon-url} -version = {addon-version} -docFileName = readme.html \ No newline at end of file +name = {addon_name} +summary = "{addon_summary}" +description = """{addon_description}""" +author = "{addon_author}" +url = {addon_url} +version = {addon_version} +docFileName = {addon_docFileName} diff --git a/sconstruct b/sconstruct index f2d91b6..e875b28 100644 --- a/sconstruct +++ b/sconstruct @@ -15,7 +15,7 @@ import buildVars def md2html(source, dest): import markdown lang = os.path.basename(os.path.dirname(source)).replace('_', '-') - title="{addonSummary} {addonVersion}".format(addonSummary=buildVars.addon_info["addon-summary"], addonVersion=buildVars.addon_info["addon-version"]) + title="{addonSummary} {addonVersion}".format(addonSummary=buildVars.addon_info["addon_summary"], addonVersion=buildVars.addon_info["addon_version"]) headerDic = { "[[!meta title=\"": "# ", "\"]]": " #", @@ -52,15 +52,10 @@ def mdTool(env): env['BUILDERS']['markdown']=mdBuilder -gettextvars={ - 'gettext_package_bugs_address' : 'nvda-translations@freelists.org', - 'gettext_package_name' : buildVars.addon_info['addon-name'], - 'gettext_package_version' : buildVars.addon_info['addon-version'] - } -env = Environment(ENV=os.environ, tools=['gettexttool', mdTool], **gettextvars) - +env = Environment(ENV=os.environ, tools=['gettexttool', mdTool]) +env.Append(**buildVars.addon_info) -addonFile = env.File("{addon-name}-{addon-version}.nvda-addon".format(**buildVars.addon_info)) +addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") def addonGenerator(target, source, env, for_signature): action = env.Action(lambda target, source, env : createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, @@ -120,7 +115,7 @@ def generateManifest(source, dest): def generateTranslatedManifest(source, language, out): _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext vars = {} - for var in ("addon-summary", "addon-description"): + for var in ("addon_summary", "addon_description"): vars[var] = _(buildVars.addon_info[var]) with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() @@ -157,10 +152,16 @@ for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) -pot = env.gettextPotFile("%s.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) +gettextvars={ + 'gettext_package_bugs_address' : 'nvda-translations@freelists.org', + 'gettext_package_name' : buildVars.addon_info['addon_name'], + 'gettext_package_version' : buildVars.addon_info['addon_version'] + } + +pot = env.gettextPotFile("${addon_name}.pot", i18nFiles, **gettextvars) env.Alias('pot', pot) env.Depends(pot, i18nFiles) -mergePot = env.gettextMergePotFile("%s-merge.pot" % "{addon-name}".format(**buildVars.addon_info), i18nFiles) +mergePot = env.gettextMergePotFile("${addon_name}-merge.pot", i18nFiles, **gettextvars) env.Alias('mergePot', mergePot) env.Depends(mergePot, i18nFiles) From 09c0854bb4bc9f21de7b3ec8d8f91cae5ba5204e Mon Sep 17 00:00:00 2001 From: Rui Batista Date: Fri, 5 Sep 2014 15:03:20 +0100 Subject: [PATCH 076/362] Update README to reflect latest template modifications. * Update copyright date * Removed configobj requirement (it never was a template requirement) * Small fixes and clarifications * Removed mention to docHandler plugin as it is not needed now. --- readme.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 3f94045..9c321ad 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ This package contains a basic template structure for NVDA add-on development, bu For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). The NVDA addon development/discussion list [is here](http://www.freelists.org/list/nvda-addons) -Copyright (C) 2012-2013 nvda addon team contributors. +Copyright (C) 2012-2014 nvda addon team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. @@ -26,8 +26,7 @@ You need the following software to use this code for your NVDA add-ons developme - a Python distribution (2.7 or greater is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. - Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. - GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). -- Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1). -- ConfigObj 4.6.2 or later to store add-on settings. You can grab the latest version here: [ConfigObj latest download](https://pypi.python.org/pypi/configobj/). +- Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `easy_install markdown`. ## Usage @@ -45,7 +44,6 @@ You need the following software to use this code for your NVDA add-ons developme - Copy the **readme.md** file for your addon, and the **docHandler.py** file, contained into addonTemplate, to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. - Documentation files (named **readme.md**) must be placed into addon\doc\/. -- Don't use **yourAddonName_docHandler.py** as a name for any file contained in **globalPlugins**; it will be removed to create a menu item for opening your addon documentation, under NVDA's help menu. ### To package the add-on for distribution: ### From 16ca7ca87df15b9af8ceb48cd09924f4663c9b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Fri, 5 Sep 2014 22:05:50 +0200 Subject: [PATCH 077/362] Readme: Fixed small errors: removed mentioned file docHandler. --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 9c321ad..1da5e44 100644 --- a/readme.md +++ b/readme.md @@ -42,7 +42,7 @@ You need the following software to use this code for your NVDA add-ons developme ### To manage documentation files for your addon: ### -- Copy the **readme.md** file for your addon, and the **docHandler.py** file, contained into addonTemplate, to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. +- Copy the **readme.md** file for your add-on to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. - Documentation files (named **readme.md**) must be placed into addon\doc\/. ### To package the add-on for distribution: ### @@ -52,4 +52,4 @@ You need the following software to use this code for your NVDA add-ons developme Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. -If you have any issues please use the NVDA addon list mensioned above. +If you have any issues please use the NVDA addon list mentioned above. From fff3ccbee2a94075b8189579232e1481ea72cec3 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 5 Sep 2014 13:14:50 -0700 Subject: [PATCH 078/362] BuildVars: remove Doc Handler from i18n sources. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 5af17b0..0f5c03c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -37,7 +37,7 @@ pythonSources = [] # Files that contain strings for translation. Usually your python sources -i18nSources = pythonSources + ["buildVars.py", "docHandler.py"] +i18nSources = pythonSources + ["buildVars.py"] # Files that will be ignored when building the nvda-addon file # Paths are relative to the addon directory, not to the root directory of your addon sources. From 083b27e1601ae1f515241e8a781464e053cd537d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 6 Sep 2014 08:02:58 +0200 Subject: [PATCH 079/362] readme: added scons_sites as folder to be copied from addonTemplate. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1da5e44..b05ba2f 100644 --- a/readme.md +++ b/readme.md @@ -35,7 +35,7 @@ You need the following software to use this code for your NVDA add-ons developme - Create an empty folder to hold the files for your add-on. - Create an **addon** folder inside this new folder. Inside **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. -- Copy the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, .gitignore and .gitattributes files to the created folder. +- Copy the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, site_scons, .gitignore and .gitattributes files to the created folder. - In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). - Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. - Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. From ff401e649eddf15c77cbda46ef0568f9190e922c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 6 Sep 2014 08:08:57 +0200 Subject: [PATCH 080/362] Changed comment: a menu item shouldn't be appended; instead the corresponding help button is enabled in add-ons manager. --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index e875b28..b77cfe6 100644 --- a/sconstruct +++ b/sconstruct @@ -144,7 +144,7 @@ for file in pythonFiles: env.Depends(addon, file) #Convert markdown files to html -createAddonHelp("addon") # We need at least doc in English and should append an item to Help menu +createAddonHelp("addon") # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): htmlFile = env.markdown(mdFile) env.Depends(htmlFile, mdFile) From 1c8c3d3f2465118b306e4268d555ed5817291891 Mon Sep 17 00:00:00 2001 From: James Teh Date: Fri, 19 Sep 2014 08:59:44 +1000 Subject: [PATCH 081/362] Fix some typos in the gettextMergePotFile scons builder which were breaking it and causing it to print weird output. --- site_scons/site_tools/gettexttool/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index 97fd629..b2e146d 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -37,7 +37,7 @@ def generate(env): suffix=".pot") env['BUILDERS']['gettextMergePotFile']=env.Builder( - action=Action("xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-ve rsion='$gettext_package_version' --omit-header --no-location -c -o $TARGET $OURCES", - "Generating pot file %TARGET"), + action=Action("xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-ve rsion='$gettext_package_version' --omit-header --no-location -c -o $TARGET $SOURCES", + "Generating pot file $TARGET"), suffix=".pot") From f31d4251e1e29a5f43852e1c36efe67141e97a86 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Fri, 19 Sep 2014 13:17:31 +0100 Subject: [PATCH 082/362] scons gettexttool: fixes/cleanups. * Fix more typos, one of which prevented "scons pot" from generating a pot file.. Problem reported by Takuya. * Break out common arguments to xgettext so that code is more readable. --- site_scons/site_tools/gettexttool/__init__.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index b2e146d..fa3a937 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -20,6 +20,13 @@ def exists(env): return True +XGETTEXT_COMMON_ARGS = ( + "--msgid-bugs-address='$gettext_package_bugs_address' " + "--package-name='$gettext_package_name' " + "--package-version='$gettext_package_version' " + "-c -o $TARGET $SOURCES" +) + def generate(env): env.SetDefault(gettext_package_bugs_address="example@example.com") env.SetDefault(gettext_package_name="") @@ -32,12 +39,11 @@ def generate(env): ) env['BUILDERS']['gettextPotFile']=env.Builder( - action=Action("xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-version='$gettext_package_version' -c -o $TARGET $SOURCE", - "Generating pot file $TARGET"), + action=Action("xgettext " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), suffix=".pot") env['BUILDERS']['gettextMergePotFile']=env.Builder( - action=Action("xgettext --msgid-bugs-address='$gettext_package_bugs_address' --package-name='$gettext_package_name' --package-ve rsion='$gettext_package_version' --omit-header --no-location -c -o $TARGET $SOURCES", - "Generating pot file $TARGET"), + action=Action("xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, + "Generating pot file $TARGET"), suffix=".pot") From 64f847032e43dc9998840ffb414dc6827a80f1b3 Mon Sep 17 00:00:00 2001 From: James Teh Date: Thu, 25 Aug 2016 16:14:48 +1000 Subject: [PATCH 083/362] Ensure that the manifest is rebuilt if buildVars.py is updated. --- sconstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sconstruct b/sconstruct index b77cfe6..c28510b 100644 --- a/sconstruct +++ b/sconstruct @@ -167,6 +167,8 @@ env.Depends(mergePot, i18nFiles) # Generate Manifest path manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl")) +# Ensure manifest is rebuilt if buildVars is updated. +env.Depends(manifest, "buildVars.py") env.Depends(addon, manifest) env.Default(addon) From 4c62a94490911a8926d3c800f4997f6054e7fb27 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 27 Mar 2017 19:54:43 -0700 Subject: [PATCH 084/362] Update copyright years --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b05ba2f..27b31a4 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ This package contains a basic template structure for NVDA add-on development, bu For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). The NVDA addon development/discussion list [is here](http://www.freelists.org/list/nvda-addons) -Copyright (C) 2012-2014 nvda addon team contributors. +Copyright (C) 2012-2017 nvda addon team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. From a4ab0a4b2393f56d51e248dcd641d97605a684be Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 25 Jul 2017 10:33:38 -0700 Subject: [PATCH 085/362] Readme: formatting changes, Markdown is now a requirement --- readme.md | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/readme.md b/readme.md index 27b31a4..4936e72 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ This package contains a basic template structure for NVDA add-on development, building, distribution and localization. For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). -The NVDA addon development/discussion list [is here](http://www.freelists.org/list/nvda-addons) +The NVDA addon development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) Copyright (C) 2012-2017 nvda addon team contributors. @@ -12,43 +12,42 @@ This package is distributed under the terms of the GNU General Public License, v This template provides the following features you can use to help NVDA add-on development: -* Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). -* Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. -* Compilation of gettext mo files before distribution, when needed. -- To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. -* Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. -* Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. +* Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). +* Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. +* Compilation of gettext mo files before distribution, when needed. + * To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. +* Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. +* Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. ## Requirements You need the following software to use this code for your NVDA add-ons development: -- a Python distribution (2.7 or greater is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. -- Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. -- GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). -- Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `easy_install markdown`. - +* a Python distribution (2.7 or greater is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. +* Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. +* GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). +* Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `easy_install markdown`. ## Usage ### To create a new NVDA add-on, taking advantage of this template: ### -- Create an empty folder to hold the files for your add-on. -- Create an **addon** folder inside this new folder. Inside **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. -- Copy the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, site_scons, .gitignore and .gitattributes files to the created folder. -- In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). -- Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. -- Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. +1. Create an empty folder to hold the files for your add-on. +2. Create an **addon** folder inside this new folder. Inside **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. +3. Copy the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, site_scons, .gitignore and .gitattributes files to the created folder. +4. In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). +5. Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. +6. Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. ### To manage documentation files for your addon: ### -- Copy the **readme.md** file for your add-on to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. -- Documentation files (named **readme.md**) must be placed into addon\doc\/. +1. Copy the **readme.md** file for your add-on to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. +2. Documentation files (named **readme.md**) must be placed into addon\doc\/. ### To package the add-on for distribution: ### -- Open a command line, change to the folder that has the **SCONSTRUCT** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. -- You can further customize variables in the **buildVars.py** file. +1. Open a command line, change to the folder that has the **SCONSTRUCT** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. +2. You can further customize variables in the **buildVars.py** file. Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From fa2ac25d5a000ba15ecbb241dfcc52eb8191ff61 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 16 Aug 2018 21:47:34 -0700 Subject: [PATCH 086/362] Update copyright years --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 4936e72..52ad312 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ This package contains a basic template structure for NVDA add-on development, bu For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). The NVDA addon development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) -Copyright (C) 2012-2017 nvda addon team contributors. +Copyright (C) 2012-2018 nvda addon team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. From 9eb75de4aa9343c83eabb59b9f467019dac2f439 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 16 Aug 2018 21:54:42 -0700 Subject: [PATCH 087/362] SConstruct: remove extra spaces --- sconstruct | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sconstruct b/sconstruct index c28510b..286caf0 100644 --- a/sconstruct +++ b/sconstruct @@ -11,7 +11,6 @@ import zipfile import buildVars - def md2html(source, dest): import markdown lang = os.path.basename(os.path.dirname(source)).replace('_', '-') @@ -51,7 +50,6 @@ def mdTool(env): ) env['BUILDERS']['markdown']=mdBuilder - env = Environment(ENV=os.environ, tools=['gettexttool', mdTool]) env.Append(**buildVars.addon_info) @@ -67,7 +65,6 @@ def manifestGenerator(target, source, env, for_signature): lambda target, source, env : "Generating manifest %s" % target[0]) return action - def translatedManifestGenerator(target, source, env, for_signature): dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) lang = os.path.basename(dir) @@ -90,8 +87,6 @@ def createAddonHelp(dir): readmeTarget = env.Command(readmePath, "readme.md", Copy("$TARGET", "$SOURCE")) env.Depends(addon, readmeTarget) - - def createAddonBundleFromPath(path, dest): """ Creates a bundle from a directory that contains an addon manifest file.""" basedir = os.path.abspath(path) From a7aca7f9780d27d4dc1030204e4571ed8623da0c Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 30 Sep 2018 03:12:24 -0700 Subject: [PATCH 088/362] SConstruct: allow developers to specify add-on version and update channel via command line. One can now specify add-on version and update channel like so: * version=something * channel=somechannel Also, if 'dev' variable is set to 'True', version becomes yyyymmdd and channel will be set to dev. This flag is meant for development releases only. --- sconstruct | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 286caf0..2069cd1 100644 --- a/sconstruct +++ b/sconstruct @@ -50,9 +50,25 @@ def mdTool(env): ) env['BUILDERS']['markdown']=mdBuilder -env = Environment(ENV=os.environ, tools=['gettexttool', mdTool]) +vars = Variables() +vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) +vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) +vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) + +env = Environment(variables=vars, ENV=os.environ, tools=['gettexttool', mdTool]) env.Append(**buildVars.addon_info) +if env["dev"]: + import datetime + buildDate = datetime.datetime.now() + year, month, day = str(buildDate.year), str(buildDate.month), str(buildDate.day) + env["addon_version"] = "".join([year, month.zfill(2), day.zfill(2), "-dev"]) + env["channel"] = "dev" +elif env["version"] is not None: + env["addon_version"] = env["version"] +if "channel" in env and env["channel"] is not None: + env["addon_updateChannel"] = env["channel"] + addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") def addonGenerator(target, source, env, for_signature): @@ -101,9 +117,12 @@ def createAddonBundleFromPath(path, dest): return dest def generateManifest(source, dest): + addon_info = buildVars.addon_info + addon_info["addon_version"] = env["addon_version"] + addon_info["addon_updateChannel"] = env["addon_updateChannel"] with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() - manifest = manifest_template.format(**buildVars.addon_info) + manifest = manifest_template.format(**addon_info) with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) From ded1bfee4845124c728e3bf5b41e07060b8cff91 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 30 Sep 2018 03:16:17 -0700 Subject: [PATCH 089/362] Build vars and manifest: add update channel and minimum NvDA version keys. In preparation for NVDA issues 3208 and 6275: allow authors to speciry add-on update channel and minimum compatible NVDA version. --- buildVars.py | 4 ++++ manifest.ini.tpl | 2 ++ 2 files changed, 6 insertions(+) diff --git a/buildVars.py b/buildVars.py index 0f5c03c..47273ea 100644 --- a/buildVars.py +++ b/buildVars.py @@ -27,6 +27,10 @@ "addon_url" : None, # Documentation file name "addon_docFileName" : "readme.html", + # Minimum NVDA version supported *e.g. "2018.3") + "addon_minimumNVDAVersion" : None, + # Add-on update channel (default is stable or None) + "addon_updateChannel" : None, } diff --git a/manifest.ini.tpl b/manifest.ini.tpl index 7de43bf..e98c9d1 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -5,3 +5,5 @@ author = "{addon_author}" url = {addon_url} version = {addon_version} docFileName = {addon_docFileName} +minimumNVDAVersion = {addon_minimumNVDAVersion} +updateChannel = {addon_updateChannel} From 7c15871b276c05ee561885e456085e7a719f0ef6 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 17 Nov 2018 17:17:28 -0800 Subject: [PATCH 090/362] BuildVars and manifest template: add last NVDA version flag. In preparation for NVDA issue 6275: add an optional varialbe to indicate the version of NVDA the add-on was last tested. --- buildVars.py | 4 +++- manifest.ini.tpl | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 47273ea..a1ebe21 100644 --- a/buildVars.py +++ b/buildVars.py @@ -27,8 +27,10 @@ "addon_url" : None, # Documentation file name "addon_docFileName" : "readme.html", - # Minimum NVDA version supported *e.g. "2018.3") + # Minimum NVDA version supported (e.g. "2018.3") "addon_minimumNVDAVersion" : None, + # Last NVDA version supported/tested (e.g. "2018.4", ideally more recent than minimum version) + "addon_lastTestedNVDAVersion" : None, # Add-on update channel (default is stable or None) "addon_updateChannel" : None, } diff --git a/manifest.ini.tpl b/manifest.ini.tpl index e98c9d1..d44355d 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -6,4 +6,5 @@ url = {addon_url} version = {addon_version} docFileName = {addon_docFileName} minimumNVDAVersion = {addon_minimumNVDAVersion} +lastTestedNVDAVersion = {addon_lastTestedNVDAVersion} updateChannel = {addon_updateChannel} From 5c72ba9be7f6042318acd159b9dda7de9f3651b6 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 1 Feb 2019 13:33:59 -0800 Subject: [PATCH 091/362] BuildVars template: include examples of year.major.minor in description. --- buildVars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index a1ebe21..28b61fb 100644 --- a/buildVars.py +++ b/buildVars.py @@ -27,9 +27,9 @@ "addon_url" : None, # Documentation file name "addon_docFileName" : "readme.html", - # Minimum NVDA version supported (e.g. "2018.3") + # Minimum NVDA version supported (e.g. "2018.3.0") "addon_minimumNVDAVersion" : None, - # Last NVDA version supported/tested (e.g. "2018.4", ideally more recent than minimum version) + # Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version) "addon_lastTestedNVDAVersion" : None, # Add-on update channel (default is stable or None) "addon_updateChannel" : None, From 27ebcf720e985df11829ae5f51a3ba0fbc581107 Mon Sep 17 00:00:00 2001 From: Julien Cochuyt Date: Tue, 19 Feb 2019 10:05:33 +0100 Subject: [PATCH 092/362] Include `pgettext` calls when extracting translatable string literals (#2) --- site_scons/site_tools/gettexttool/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index fa3a937..8bb1b8d 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -24,6 +24,7 @@ def exists(env): "--msgid-bugs-address='$gettext_package_bugs_address' " "--package-name='$gettext_package_name' " "--package-version='$gettext_package_version' " + "--keyword=pgettext:1c,2 " "-c -o $TARGET $SOURCES" ) From 57d176ac054137d4497b5e8b5d7e94cd7f123bdb Mon Sep 17 00:00:00 2001 From: Julien Cochuyt Date: Sun, 14 Oct 2018 12:16:58 +0200 Subject: [PATCH 093/362] Doc style sheet: Remove inverted color scheme (#4) --- style.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/style.css b/style.css index 373283f..90f99d1 100644 --- a/style.css +++ b/style.css @@ -1,8 +1,6 @@ @charset "utf-8"; body { font-family : Verdana, Arial, Helvetica, Sans-serif; -color : #FFFFFF; -background-color : #000000; line-height: 1.2em; } h1, h2 {text-align: center} @@ -26,5 +24,3 @@ a { text-decoration : underline; text-decoration : none; } a:focus, a:hover {outline: solid} -:link {color: #0000FF; -background-color: #FFFFFF} From 041890c13315b7eb9ddcfb71883a49c97cae3df2 Mon Sep 17 00:00:00 2001 From: Julien Cochuyt Date: Mon, 22 Oct 2018 00:30:49 +0200 Subject: [PATCH 094/362] .gitignore: Ignore .pyo files (#9) --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6d124be..a304182 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,6 @@ addon/doc/en/ *.ini *.mo *.pot -*.pyc +*.py[co] *.nvda-addon .sconsign.dblite From 656a3aaef3be7793917157f1396c6e4724e60682 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 18 Jul 2019 19:11:25 -0700 Subject: [PATCH 095/362] Build vars/manifest: clarification on minimum version flag. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 28b61fb..142cdd9 100644 --- a/buildVars.py +++ b/buildVars.py @@ -27,7 +27,7 @@ "addon_url" : None, # Documentation file name "addon_docFileName" : "readme.html", - # Minimum NVDA version supported (e.g. "2018.3.0") + # Minimum NVDA version supported (e.g. "2018.3.0", minor version is optional) "addon_minimumNVDAVersion" : None, # Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version) "addon_lastTestedNVDAVersion" : None, From 647d179d5ecae7751e0126d9e2a62a422ca47490 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 18 Jul 2019 19:11:39 -0700 Subject: [PATCH 096/362] BuildVars: change guidelines ilnk. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 142cdd9..7a081fe 100644 --- a/buildVars.py +++ b/buildVars.py @@ -9,7 +9,7 @@ # Add-on information variables addon_info = { # for previously unpublished addons, please follow the community guidelines at: - # https://bitbucket.org/nvdaaddonteam/todo/raw/master/guideLines.txt + # https://bitbucket.org/nvdaaddonteam/todo/raw/master/guidelines.txt # add-on Name, internal for nvda "addon_name" : "addonTemplate", # Add-on summary, usually the user visible name of the addon. From 207900f3019884d282fe25ed690a52167b3605aa Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 18 Jul 2019 19:12:29 -0700 Subject: [PATCH 097/362] Readme: update copyright years --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 52ad312..798c8f1 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ This package contains a basic template structure for NVDA add-on development, bu For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). The NVDA addon development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) -Copyright (C) 2012-2018 nvda addon team contributors. +Copyright (C) 2012-2019 nvda addon team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. From d2fb1d4af530e24238d0afafcda0f375317a9a1a Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Thu, 18 Jul 2019 19:20:11 -0700 Subject: [PATCH 098/362] Readme: cosmetics and heading markup change. --- readme.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 798c8f1..0e765dc 100644 --- a/readme.md +++ b/readme.md @@ -30,23 +30,23 @@ You need the following software to use this code for your NVDA add-ons developme ## Usage -### To create a new NVDA add-on, taking advantage of this template: ### +### To create a new NVDA add-on, taking advantage of this template: 1. Create an empty folder to hold the files for your add-on. -2. Create an **addon** folder inside this new folder. Inside **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. -3. Copy the **buildVars.py** file, the manifest.ini.tpl file, the manifest-translated.ini.tpl, **SCONSTRUCT**, site_scons, .gitignore and .gitattributes files to the created folder. +2. Copy the **site_scons** folder, and the following files, into your new empty folder: **buildVars.py**, **manifest.ini.tpl**, **manifest-translated.ini.tpl**, **sconstruct**, **.gitignore**, and **.gitattributes** +3. Create an **addon** folder inside your new folder. Inside the **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. 4. In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). 5. Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. 6. Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. -### To manage documentation files for your addon: ### +### To manage documentation files for your addon: 1. Copy the **readme.md** file for your add-on to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. 2. Documentation files (named **readme.md**) must be placed into addon\doc\/. -### To package the add-on for distribution: ### ++### To package the add-on for distribution: -1. Open a command line, change to the folder that has the **SCONSTRUCT** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. +1. Open a command line, change to the folder that has the **sconstruct** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. 2. You can further customize variables in the **buildVars.py** file. Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From bb2dc6e4fef64d6cc76669644a10630e6faac5dc Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 27 Jul 2019 09:08:10 -0700 Subject: [PATCH 099/362] NVDA translations list is now hosted on Groups.IO --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 2069cd1..0988d63 100644 --- a/sconstruct +++ b/sconstruct @@ -167,7 +167,7 @@ for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) gettextvars={ - 'gettext_package_bugs_address' : 'nvda-translations@freelists.org', + 'gettext_package_bugs_address' : 'nvda-translations@groups.io', 'gettext_package_name' : buildVars.addon_info['addon_name'], 'gettext_package_version' : buildVars.addon_info['addon_version'] } From bcdfada9145c6d5ce936b811864b8480d492ba36 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 27 Jul 2019 10:33:40 -0700 Subject: [PATCH 100/362] Python 3: various edits for sconstruct. dict.iteritems -> dict.items, ugettext -> gettext with Python version check. --- sconstruct | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 0988d63..60af457 100644 --- a/sconstruct +++ b/sconstruct @@ -21,7 +21,7 @@ def md2html(source, dest): } with codecs.open(source, "r", "utf-8") as f: mdText = f.read() - for k, v in headerDic.iteritems(): + for k, v in headerDic.items(): mdText = mdText.replace(k, v, 1) htmlText = markdown.markdown(mdText) with codecs.open(dest, "w", "utf-8") as f: @@ -127,7 +127,12 @@ def generateManifest(source, dest): f.write(manifest) def generateTranslatedManifest(source, language, out): - _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext + # No ugettext in Python 3. + import sys + if sys.version_info.major == 2: + _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext + else: + _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).gettext vars = {} for var in ("addon_summary", "addon_description"): vars[var] = _(buildVars.addon_info[var]) From 546fbc30b515951f650e2d307683a44dd5e1fcba Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 28 Jul 2019 11:31:14 -0700 Subject: [PATCH 101/362] Python 2/3: do not write bytecode and remove dblite file. Previously bytecode was written, which meant it wasn't cleaned up properly when scons --clean was executed. Also, if .dblite file exists, Python will get confused regarding pickle protocol (2 to 3). Therefore do not write bytecode and remove dblite (and English readme folder). Credit: Abdel. --- sconstruct | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 60af457..600db4a 100644 --- a/sconstruct +++ b/sconstruct @@ -8,6 +8,8 @@ import gettext import os import os.path import zipfile +import sys +sys.dont_write_bytecode = True import buildVars @@ -128,7 +130,6 @@ def generateManifest(source, dest): def generateTranslatedManifest(source, language, out): # No ugettext in Python 3. - import sys if sys.version_info.major == 2: _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext else: @@ -191,3 +192,4 @@ env.Depends(manifest, "buildVars.py") env.Depends(addon, manifest) env.Default(addon) +env.Clean (addon, ['.sconsign.dblite', 'addon/doc/en/']) From ac8b548de04af5120b2bd60221261ac4ab5a8bb4 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 10 Aug 2019 21:43:29 -0700 Subject: [PATCH 102/362] Update channel: clarify about None versus other channels, add a warning that people should not change this unless one knows what's up. --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 7a081fe..971a48a 100644 --- a/buildVars.py +++ b/buildVars.py @@ -31,7 +31,7 @@ "addon_minimumNVDAVersion" : None, # Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version) "addon_lastTestedNVDAVersion" : None, - # Add-on update channel (default is stable or None) + # Add-on update channel (default is None, denoting stable releases, and for development releases, use "dev"; do not change unless you know what you are doing) "addon_updateChannel" : None, } From 45507591d9e3456a5e8ef41b11155273573a859b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Fri, 3 Jan 2020 18:31:38 +0100 Subject: [PATCH 103/362] Convert markdown to HTML 5 --- sconstruct | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sconstruct b/sconstruct index 600db4a..5f8a7d9 100644 --- a/sconstruct +++ b/sconstruct @@ -27,13 +27,12 @@ def md2html(source, dest): mdText = mdText.replace(k, v, 1) htmlText = markdown.markdown(mdText) with codecs.open(dest, "w", "utf-8") as f: - f.write("\n" + - "\n" + - "\n" % (lang, lang) + + f.write("\n" + + "\n" % lang + "\n" + - "\n" + - "\n" + + "\n" + + "\n" + + "\n" + "%s\n" % title + "\n\n" ) From 66e54e4ec165439ad6f1fcf37d215ae53f11aca0 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 30 Apr 2020 12:33:00 -0700 Subject: [PATCH 104/362] BuildVars: no whitespace between dictionary key and colon (Flake8 E203) --- buildVars.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/buildVars.py b/buildVars.py index 971a48a..3fc637b 100644 --- a/buildVars.py +++ b/buildVars.py @@ -4,35 +4,35 @@ # Change this file instead of sconstruct or manifest files, whenever possible. # Full getext (please don't change) -_ = lambda x : x +_ = lambda x: x # Add-on information variables addon_info = { # for previously unpublished addons, please follow the community guidelines at: # https://bitbucket.org/nvdaaddonteam/todo/raw/master/guidelines.txt # add-on Name, internal for nvda - "addon_name" : "addonTemplate", + "addon_name": "addonTemplate", # Add-on summary, usually the user visible name of the addon. # Translators: Summary for this add-on to be shown on installation and add-on information. - "addon_summary" : _("Add-on user visible name"), + "addon_summary": _("Add-on user visible name"), # Add-on description # Translators: Long description to be shown for this add-on on add-on information from add-ons manager - "addon_description" : _("""Description for the add-on. + "addon_description": _("""Description for the add-on. It can span multiple lines."""), # version - "addon_version" : "x.y", + "addon_version": "x.y", # Author(s) - "addon_author" : u"name ", + "addon_author": u"name ", # URL for the add-on documentation support - "addon_url" : None, + "addon_url": None, # Documentation file name - "addon_docFileName" : "readme.html", + "addon_docFileName": "readme.html", # Minimum NVDA version supported (e.g. "2018.3.0", minor version is optional) - "addon_minimumNVDAVersion" : None, + "addon_minimumNVDAVersion": None, # Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version) - "addon_lastTestedNVDAVersion" : None, + "addon_lastTestedNVDAVersion": None, # Add-on update channel (default is None, denoting stable releases, and for development releases, use "dev"; do not change unless you know what you are doing) - "addon_updateChannel" : None, + "addon_updateChannel": None, } From 728ecc5fdd0accbccea3bc027a5e9938cd7373f5 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 5 May 2020 01:09:31 -0700 Subject: [PATCH 105/362] Sconstruct: update copyright header (also complies with Flake8) --- sconstruct | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index 5f8a7d9..7ee1301 100644 --- a/sconstruct +++ b/sconstruct @@ -1,7 +1,7 @@ # NVDA add-on template SCONSTRUCT file -#Copyright (C) 2012, 2014 Rui Batista -#This file is covered by the GNU General Public License. -#See the file COPYING.txt for more details. +# Copyright (C) 2012-2020 Rui Batista, Noelia Martinez, Joseph Lee +# This file is covered by the GNU General Public License. +# See the file COPYING.txt for more details. import codecs import gettext From c709afadbc53e728ac3fc11e68999beea27cc9a5 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 5 May 2020 01:11:31 -0700 Subject: [PATCH 106/362] Add-on version: update buildVars.addon_info with custom version and update channel coming from command line, mostly used to provide correct version for the resulting add-on documentation. Fixes #13. Suppose an author provides custom version on the command line. Manifest is correct, but documentation version isn't, as the title derives from buildVars map. Thus update buildVars with custom version and update channel coming from command line if this is the case. --- sconstruct | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 7ee1301..cd0e5e8 100644 --- a/sconstruct +++ b/sconstruct @@ -70,6 +70,9 @@ elif env["version"] is not None: if "channel" in env and env["channel"] is not None: env["addon_updateChannel"] = env["channel"] +buildVars.addon_info["addon_version"] = env["addon_version"] +buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] + addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") def addonGenerator(target, source, env, for_signature): @@ -119,8 +122,6 @@ def createAddonBundleFromPath(path, dest): def generateManifest(source, dest): addon_info = buildVars.addon_info - addon_info["addon_version"] = env["addon_version"] - addon_info["addon_updateChannel"] = env["addon_updateChannel"] with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() manifest = manifest_template.format(**addon_info) From 5fbad29105125187b4aded58b54dd9cd408d3a69 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 4 Sep 2020 20:24:23 -0700 Subject: [PATCH 107/362] BuildVars: remove now obsolete and nonexistent Bitbucket URL. Fixes #14. As Bitbucket repo for 'Todo' repo is gone, do not keep this around anymore. --- buildVars.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/buildVars.py b/buildVars.py index 3fc637b..f996566 100644 --- a/buildVars.py +++ b/buildVars.py @@ -8,9 +8,7 @@ # Add-on information variables addon_info = { - # for previously unpublished addons, please follow the community guidelines at: - # https://bitbucket.org/nvdaaddonteam/todo/raw/master/guidelines.txt - # add-on Name, internal for nvda + # add-on Name/identifier, internal for NVDA "addon_name": "addonTemplate", # Add-on summary, usually the user visible name of the addon. # Translators: Summary for this add-on to be shown on installation and add-on information. From ed8e2e77504c0edaeb2da4a7d4574cff65e0c9aa Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 4 Sep 2020 20:25:07 -0700 Subject: [PATCH 108/362] BuildVars: comment edits and no more 'u' prefix in add-on author field. --- buildVars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index f996566..5326262 100644 --- a/buildVars.py +++ b/buildVars.py @@ -11,7 +11,7 @@ # add-on Name/identifier, internal for NVDA "addon_name": "addonTemplate", # Add-on summary, usually the user visible name of the addon. - # Translators: Summary for this add-on to be shown on installation and add-on information. + # Translators: Summary for this add-on to be shown on installation and add-on information found in Add-ons Manager. "addon_summary": _("Add-on user visible name"), # Add-on description # Translators: Long description to be shown for this add-on on add-on information from add-ons manager @@ -20,7 +20,7 @@ # version "addon_version": "x.y", # Author(s) - "addon_author": u"name ", + "addon_author": "name ", # URL for the add-on documentation support "addon_url": None, # Documentation file name From 75f08f5db5d3379ad9ebbed179cb5c7fa81f04c0 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 4 Sep 2020 20:25:38 -0700 Subject: [PATCH 109/362] Readme: add a dedicated add-on manifest section and update dependencies. --- readme.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 0e765dc..6730988 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ This package is distributed under the terms of the GNU General Public License, v This template provides the following features you can use to help NVDA add-on development: * Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). -* Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. +* Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. See below for add-on manifest specification. * Compilation of gettext mo files before distribution, when needed. * To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. @@ -23,8 +23,8 @@ This template provides the following features you can use to help NVDA add-on de You need the following software to use this code for your NVDA add-ons development: -* a Python distribution (2.7 or greater is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. -* Scons - [Website](http://www.scons.org/) - version 2.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. +* a Python distribution (3.7 or later is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. +* Scons - [Website](http://www.scons.org/) - version 3.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). * Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `easy_install markdown`. @@ -39,12 +39,27 @@ You need the following software to use this code for your NVDA add-ons developme 5. Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. 6. Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. +#### Add-on manifest specification + +An add-on manifest generated manually or via **buildVars.py** must include the following information: + +* Name (string): a unique identifier for the add-on. It must use camel case (e.g. someModule). +* Summary (string): name as shown on NVDA's Add-ons Manager. +* Description (string): a short detailed description about the add-on. +* Version (string) +* Author (string and an email address): one or more add-on author contact information in the form "name ". +* URL (string): a web address where the add-on information can be found (typically community add-ons website address (https://addons.nvda-project.org) is used). +* docFileName (string): name of the documentation file. +* minimumNVDAVersion (year.major or year.major.minor): the earliest version of NVDA the add-on is compatible with (e.g. 2019.3). Add-ons are expected to use features introduced in this version of NVDA or declare compatibility with it. +* lastTestedNVDAVersion (year.major or year.major.minor): the latest or last tested version of NVDA the add-on is said to be compatible with (e.g. 2020.3). Add-on authors are expected to declare this value after testing add-ons with the version of NVDA specified. +* addon_updateChannel (string or None): the update channel for the add-on release. + ### To manage documentation files for your addon: 1. Copy the **readme.md** file for your add-on to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. 2. Documentation files (named **readme.md**) must be placed into addon\doc\/. -+### To package the add-on for distribution: +### To package the add-on for distribution: 1. Open a command line, change to the folder that has the **sconstruct** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. 2. You can further customize variables in the **buildVars.py** file. From 47b1a534689399d4dfe231e777ccd008e8ccbfd9 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 4 Sep 2020 20:25:53 -0700 Subject: [PATCH 110/362] Readme: additional edits and copyright year update --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 6730988..8eaf4fc 100644 --- a/readme.md +++ b/readme.md @@ -1,10 +1,10 @@ # NVDA Add-on Scons Template # This package contains a basic template structure for NVDA add-on development, building, distribution and localization. -For details about NVDA add-on development please see the [NVDA Developer Guide](http://www.nvda-project.org/documentation/developerGuide.html). +For details about NVDA add-on development, please see the [NVDA Add-on Development Guide](https://github.com/nvdaaddons/DevGuide/wiki/NVDA-Add-on-Development-Guide). The NVDA addon development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) -Copyright (C) 2012-2019 nvda addon team contributors. +Copyright (C) 2012-2020 nvda addon team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. From 7898664458af905380b80f470a0f35626a679a2a Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 5 Sep 2020 09:33:59 -0700 Subject: [PATCH 111/362] Flake8 E205/E205: blank lines between function bodies in gettext tool --- site_scons/site_tools/gettexttool/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index 8bb1b8d..a48c8cc 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -17,9 +17,11 @@ """ from SCons.Action import Action + def exists(env): return True + XGETTEXT_COMMON_ARGS = ( "--msgid-bugs-address='$gettext_package_bugs_address' " "--package-name='$gettext_package_name' " @@ -28,6 +30,7 @@ def exists(env): "-c -o $TARGET $SOURCES" ) + def generate(env): env.SetDefault(gettext_package_bugs_address="example@example.com") env.SetDefault(gettext_package_name="") From a1f8e91a0d68a7029b3498f4cc2659cd421298f2 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 5 Sep 2020 09:34:40 -0700 Subject: [PATCH 112/362] Flake8 E225: space between equals operands --- site_scons/site_tools/gettexttool/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index a48c8cc..f485805 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -36,17 +36,17 @@ def generate(env): env.SetDefault(gettext_package_name="") env.SetDefault(gettext_package_version="") - env['BUILDERS']['gettextMoFile']=env.Builder( + env['BUILDERS']['gettextMoFile'] = env.Builder( action=Action("msgfmt -o $TARGET $SOURCE", "Compiling translation $SOURCE"), suffix=".mo", src_suffix=".po" ) - env['BUILDERS']['gettextPotFile']=env.Builder( + env['BUILDERS']['gettextPotFile'] = env.Builder( action=Action("xgettext " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), suffix=".pot") - env['BUILDERS']['gettextMergePotFile']=env.Builder( + env['BUILDERS']['gettextMergePotFile'] = env.Builder( action=Action("xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), suffix=".pot") From 698b001312bbe8c7a12a1c84de2d5408e0518735 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 5 Sep 2020 09:34:53 -0700 Subject: [PATCH 113/362] Flake8 W391: no blank line at end of file --- site_scons/site_tools/gettexttool/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index f485805..46358ca 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -50,4 +50,3 @@ def generate(env): action=Action("xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), suffix=".pot") - From a68456e8a34e0fa5d4ecd1d3d9db9aac5883961c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 19:14:03 +0200 Subject: [PATCH 114/362] gettextool fix Flake8 errors ET113 and ET128 --- site_scons/site_tools/gettexttool/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index 46358ca..db9a009 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -47,6 +47,9 @@ def generate(env): suffix=".pot") env['BUILDERS']['gettextMergePotFile'] = env.Builder( - action=Action("xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, - "Generating pot file $TARGET"), - suffix=".pot") + action=Action( + "xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, + "Generating pot file $TARGET" + ), + suffix=".pot" + ) From 63e1acea6ceff9dd061c6acfffb7b628223bd605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 19:17:46 +0200 Subject: [PATCH 115/362] buildVars: Do not assign a lambda (Flake8 E731) --- buildVars.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 5326262..ad372b0 100644 --- a/buildVars.py +++ b/buildVars.py @@ -3,8 +3,11 @@ # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. + # Full getext (please don't change) -_ = lambda x: x +def _(arg): + return arg + # Add-on information variables addon_info = { From a44bee1ccb8f1e2261475cb31a3127f1a17ee564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 19:22:33 +0200 Subject: [PATCH 116/362] BuildVars: Split some long lines (Flake8 E501) --- buildVars.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index ad372b0..ef88e97 100644 --- a/buildVars.py +++ b/buildVars.py @@ -14,7 +14,8 @@ def _(arg): # add-on Name/identifier, internal for NVDA "addon_name": "addonTemplate", # Add-on summary, usually the user visible name of the addon. - # Translators: Summary for this add-on to be shown on installation and add-on information found in Add-ons Manager. + # Translators: Summary for this add-on + # to be shown on installation and add-on information found in Add-ons Manager. "addon_summary": _("Add-on user visible name"), # Add-on description # Translators: Long description to be shown for this add-on on add-on information from add-ons manager @@ -32,7 +33,9 @@ def _(arg): "addon_minimumNVDAVersion": None, # Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version) "addon_lastTestedNVDAVersion": None, - # Add-on update channel (default is None, denoting stable releases, and for development releases, use "dev"; do not change unless you know what you are doing) + # Add-on update channel (default is None, denoting stable releases, + # and for development releases, use "dev".) + # Ddo not change unless you know what you are doing! "addon_updateChannel": None, } From ff7e9c9d2f9bb37e053e99ee3707c5478baad59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 19:24:38 +0200 Subject: [PATCH 117/362] BuildVars: Remove unused import - add explanatory commend (flake8 E402 and F401) --- buildVars.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index ef88e97..23fcafa 100644 --- a/buildVars.py +++ b/buildVars.py @@ -40,10 +40,9 @@ def _(arg): } -import os.path - # Define the python files that are the sources of your add-on. # You can use glob expressions here, they will be expanded. +# Fell free to import `os.path` at the top if you need to pythonSources = [] # Files that contain strings for translation. Usually your python sources From 9424a54d00f1512cf13a0c27e407952208fa3318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 19:51:46 +0200 Subject: [PATCH 118/362] Sconstruct: No space before colon (E203) and split some long lines (E501) --- sconstruct | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/sconstruct b/sconstruct index cd0e5e8..8156e01 100644 --- a/sconstruct +++ b/sconstruct @@ -16,7 +16,9 @@ import buildVars def md2html(source, dest): import markdown lang = os.path.basename(os.path.dirname(source)).replace('_', '-') - title="{addonSummary} {addonVersion}".format(addonSummary=buildVars.addon_info["addon_summary"], addonVersion=buildVars.addon_info["addon_version"]) + title="{addonSummary} {addonVersion}".format( + addonSummary=buildVars.addon_info["addon_summary"], addonVersion=buildVars.addon_info["addon_version"] + ) headerDic = { "[[!meta title=\"": "# ", "\"]]": " #", @@ -76,20 +78,26 @@ buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") def addonGenerator(target, source, env, for_signature): - action = env.Action(lambda target, source, env : createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, - lambda target, source, env : "Generating Addon %s" % target[0]) + action = env.Action( + lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, + lambda target, source, env: "Generating Addon %s" % target[0] + ) return action def manifestGenerator(target, source, env, for_signature): - action = env.Action(lambda target, source, env : generateManifest(source[0].abspath, target[0].abspath) and None, - lambda target, source, env : "Generating manifest %s" % target[0]) + action = env.Action( + lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, + lambda target, source, env: "Generating manifest %s" % target[0] + ) return action def translatedManifestGenerator(target, source, env, for_signature): dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) lang = os.path.basename(dir) - action = env.Action(lambda target, source, env : generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None, - lambda target, source, env : "Generating translated manifest %s" % target[0]) + action = env.Action( + lambda target, source, env: generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None, + lambda target, source, env: "Generating translated manifest %s" % target[0] + ) return action env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) @@ -155,7 +163,10 @@ for dir in langDirs: poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) moFile=env.gettextMoFile(poFile) env.Depends(moFile, poFile) - translatedManifest = env.NVDATranslatedManifest(dir.File("manifest.ini"), [moFile, os.path.join("manifest-translated.ini.tpl")]) + translatedManifest = env.NVDATranslatedManifest( + dir.File("manifest.ini"), + [moFile, os.path.join("manifest-translated.ini.tpl")] + ) env.Depends(translatedManifest, ["buildVars.py"]) env.Depends(addon, [translatedManifest, moFile]) @@ -164,7 +175,8 @@ for file in pythonFiles: env.Depends(addon, file) #Convert markdown files to html -createAddonHelp("addon") # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager +# We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager +createAddonHelp("addon") for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): htmlFile = env.markdown(mdFile) env.Depends(htmlFile, mdFile) @@ -173,9 +185,9 @@ for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) gettextvars={ - 'gettext_package_bugs_address' : 'nvda-translations@groups.io', - 'gettext_package_name' : buildVars.addon_info['addon_name'], - 'gettext_package_version' : buildVars.addon_info['addon_version'] + 'gettext_package_bugs_address': 'nvda-translations@groups.io', + 'gettext_package_name': buildVars.addon_info['addon_name'], + 'gettext_package_version': buildVars.addon_info['addon_version'] } pot = env.gettextPotFile("${addon_name}.pot", i18nFiles, **gettextvars) From 15e2eaff1f5892a521b7b2ff19e1958eb2c89a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 19:57:40 +0200 Subject: [PATCH 119/362] Sconstruct: Two blank lines before functions and variables (Flake8 E302 E305) --- sconstruct | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sconstruct b/sconstruct index 8156e01..f3e1f32 100644 --- a/sconstruct +++ b/sconstruct @@ -13,6 +13,7 @@ sys.dont_write_bytecode = True import buildVars + def md2html(source, dest): import markdown lang = os.path.basename(os.path.dirname(source)).replace('_', '-') @@ -41,6 +42,7 @@ def md2html(source, dest): f.write(htmlText) f.write("\n\n") + def mdTool(env): mdAction=env.Action( lambda target,source,env: md2html(source[0].path, target[0].path), @@ -53,6 +55,7 @@ def mdTool(env): ) env['BUILDERS']['markdown']=mdBuilder + vars = Variables() vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) @@ -77,6 +80,7 @@ buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") + def addonGenerator(target, source, env, for_signature): action = env.Action( lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, @@ -84,6 +88,7 @@ def addonGenerator(target, source, env, for_signature): ) return action + def manifestGenerator(target, source, env, for_signature): action = env.Action( lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, @@ -91,6 +96,7 @@ def manifestGenerator(target, source, env, for_signature): ) return action + def translatedManifestGenerator(target, source, env, for_signature): dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) lang = os.path.basename(dir) @@ -100,10 +106,12 @@ def translatedManifestGenerator(target, source, env, for_signature): ) return action + env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) env['BUILDERS']['NVDAManifest'] = Builder(generator=manifestGenerator) env['BUILDERS']['NVDATranslatedManifest'] = Builder(generator=translatedManifestGenerator) + def createAddonHelp(dir): docsDir = os.path.join(dir, "doc") if os.path.isfile("style.css"): @@ -115,6 +123,7 @@ def createAddonHelp(dir): readmeTarget = env.Command(readmePath, "readme.md", Copy("$TARGET", "$SOURCE")) env.Depends(addon, readmeTarget) + def createAddonBundleFromPath(path, dest): """ Creates a bundle from a directory that contains an addon manifest file.""" basedir = os.path.abspath(path) @@ -128,6 +137,7 @@ def createAddonBundleFromPath(path, dest): if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle) return dest + def generateManifest(source, dest): addon_info = buildVars.addon_info with codecs.open(source, "r", "utf-8") as f: @@ -136,6 +146,7 @@ def generateManifest(source, dest): with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) + def generateTranslatedManifest(source, language, out): # No ugettext in Python 3. if sys.version_info.major == 2: @@ -151,9 +162,11 @@ def generateTranslatedManifest(source, language, out): with codecs.open(out, "w", "utf-8") as f: f.write(result) + def expandGlobs(files): return [f for pattern in files for f in env.Glob(pattern)] + addon = env.NVDAAddon(addonFile, env.Dir('addon')) langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] From 4d1a3997435634e735b720d83d3fbb69f2b89f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 20:08:10 +0200 Subject: [PATCH 120/362] Sconstruct: White space consistency (Flake8 E211, E225, E228, E231) --- sconstruct | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sconstruct b/sconstruct index f3e1f32..ce32100 100644 --- a/sconstruct +++ b/sconstruct @@ -17,7 +17,7 @@ import buildVars def md2html(source, dest): import markdown lang = os.path.basename(os.path.dirname(source)).replace('_', '-') - title="{addonSummary} {addonVersion}".format( + title = "{addonSummary} {addonVersion}".format( addonSummary=buildVars.addon_info["addon_summary"], addonVersion=buildVars.addon_info["addon_version"] ) headerDic = { @@ -44,16 +44,16 @@ def md2html(source, dest): def mdTool(env): - mdAction=env.Action( - lambda target,source,env: md2html(source[0].path, target[0].path), - lambda target,source,env: 'Generating %s'%target[0], + mdAction = env.Action( + lambda target, source, env: md2html(source[0].path, target[0].path), + lambda target, source, env: 'Generating % s' % target[0], ) - mdBuilder=env.Builder( + mdBuilder = env.Builder( action=mdAction, suffix='.html', src_suffix='.md', ) - env['BUILDERS']['markdown']=mdBuilder + env['BUILDERS']['markdown'] = mdBuilder vars = Variables() @@ -174,7 +174,7 @@ langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] #Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated for dir in langDirs: poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) - moFile=env.gettextMoFile(poFile) + moFile = env.gettextMoFile(poFile) env.Depends(moFile, poFile) translatedManifest = env.NVDATranslatedManifest( dir.File("manifest.ini"), @@ -197,7 +197,7 @@ for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) -gettextvars={ +gettextvars = { 'gettext_package_bugs_address': 'nvda-translations@groups.io', 'gettext_package_name': buildVars.addon_info['addon_name'], 'gettext_package_version': buildVars.addon_info['addon_version'] @@ -217,4 +217,4 @@ env.Depends(manifest, "buildVars.py") env.Depends(addon, manifest) env.Default(addon) -env.Clean (addon, ['.sconsign.dblite', 'addon/doc/en/']) +env.Clean(addon, ['.sconsign.dblite', 'addon/doc/en/']) From 5868a7f1a1d52bc34532ae9a7faff5e640e35b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 20:12:20 +0200 Subject: [PATCH 121/362] Sconstruct: Consistent indentation for dictionaries. --- sconstruct | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index ce32100..9a31c78 100644 --- a/sconstruct +++ b/sconstruct @@ -198,10 +198,10 @@ for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) gettextvars = { - 'gettext_package_bugs_address': 'nvda-translations@groups.io', - 'gettext_package_name': buildVars.addon_info['addon_name'], - 'gettext_package_version': buildVars.addon_info['addon_version'] - } + 'gettext_package_bugs_address': 'nvda-translations@groups.io', + 'gettext_package_name': buildVars.addon_info['addon_name'], + 'gettext_package_version': buildVars.addon_info['addon_version'] +} pot = env.gettextPotFile("${addon_name}.pot", i18nFiles, **gettextvars) env.Alias('pot', pot) From cf6a88e4b10684094c81678524e9c066affddd9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 20:13:55 +0200 Subject: [PATCH 122/362] Sconstructt: Commends should start with "# " (Flake8 E265) --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 9a31c78..a467a68 100644 --- a/sconstruct +++ b/sconstruct @@ -171,7 +171,7 @@ addon = env.NVDAAddon(addonFile, env.Dir('addon')) langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] -#Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated +# Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated for dir in langDirs: poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) moFile = env.gettextMoFile(poFile) @@ -187,7 +187,7 @@ pythonFiles = expandGlobs(buildVars.pythonSources) for file in pythonFiles: env.Depends(addon, file) -#Convert markdown files to html +# Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager createAddonHelp("addon") for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): From f85bf08c441f70dfecd09336ee23ee8198d7be3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Wed, 23 Sep 2020 20:15:37 +0200 Subject: [PATCH 123/362] Sconstruct: No multiple statements on one line (Flake8 E701) --- sconstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index a467a68..47aa8ff 100644 --- a/sconstruct +++ b/sconstruct @@ -134,7 +134,8 @@ def createAddonBundleFromPath(path, dest): for filename in filenames: pathInBundle = os.path.join(relativePath, filename) absPath = os.path.join(dir, filename) - if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle) + if pathInBundle not in buildVars.excludedFiles: + z.write(absPath, pathInBundle) return dest From 6c6c1de4865e96fc887b9d80d9773563af723b43 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 25 Sep 2020 18:10:45 -0700 Subject: [PATCH 124/362] BuildVars: spelling fixes, restore 'import os.path' with a NO QA flag. Restore 'import os.path' to reduce confusion and to make the template backward compatible. --- buildVars.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index 23fcafa..6a2f812 100644 --- a/buildVars.py +++ b/buildVars.py @@ -35,14 +35,16 @@ def _(arg): "addon_lastTestedNVDAVersion": None, # Add-on update channel (default is None, denoting stable releases, # and for development releases, use "dev".) - # Ddo not change unless you know what you are doing! + # Do not change unless you know what you are doing! "addon_updateChannel": None, } +import os.path # NOQA + + # Define the python files that are the sources of your add-on. # You can use glob expressions here, they will be expanded. -# Fell free to import `os.path` at the top if you need to pythonSources = [] # Files that contain strings for translation. Usually your python sources From 78500f74677c5c42f29240968a82752fd217fa26 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 01:30:38 -0700 Subject: [PATCH 125/362] BuildVars: restore lambda assignment (never, EVER change this line as indicated in the comment above). --- buildVars.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index 6a2f812..c3c853c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -5,8 +5,7 @@ # Full getext (please don't change) -def _(arg): - return arg +_ = lambda x: x # NOQA: E731 # Never, EVER change this line # Add-on information variables From b7b90d6fff744a0edc30e1d4e8c416c56d985296 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 01:41:31 -0700 Subject: [PATCH 126/362] SConstruct: do not allow build vars bytecode to be writtne (Flake8 E402 is hereby ignored). To keep add-on repositories clean, do not write bytecode for build vars module. To do so, Flake8 E402 is ignored. --- sconstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 47aa8ff..71e5f59 100644 --- a/sconstruct +++ b/sconstruct @@ -11,7 +11,8 @@ import zipfile import sys sys.dont_write_bytecode = True -import buildVars +# Bytecode should not be written for build vars module to keep the repository root folder clean. +import buildVars # NOQA: E402 def md2html(source, dest): From 2e4619a1103732d4168698fb4740271822957c1b Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 01:42:38 -0700 Subject: [PATCH 127/362] SConstruct: put '+' at the beginning of each readme HTML header. To guard against Flake8 E504, put '+' in front of each HTML header component. --- sconstruct | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sconstruct b/sconstruct index 71e5f59..52a70ce 100644 --- a/sconstruct +++ b/sconstruct @@ -31,14 +31,15 @@ def md2html(source, dest): mdText = mdText.replace(k, v, 1) htmlText = markdown.markdown(mdText) with codecs.open(dest, "w", "utf-8") as f: - f.write("\n" + - "\n" % lang + - "\n" + - "\n" + - "\n" + - "\n" + - "%s\n" % title + - "\n\n" + f.write( + "\n" + + "\n" % lang + + "\n" + + "\n" + + "\n" + + "\n" + + "%s\n" % title + + "\n\n" ) f.write(htmlText) f.write("\n\n") From e068f3b926edb00ffc43f3a42f0d39c83f8d70f1 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 01:59:16 -0700 Subject: [PATCH 128/362] SConstruct/documentation generation optimization: write HTML text in one go instead of writing components (header, body, end) separately. Rather than calling file.write call three times (to write HTML header, body, and end), build the md2html doc text in one go and write it, using str.join to join a list of HTML tags and components together. This optimization also fixes various Flake8 errors, in particular E503 as '+' is no longer inserted at the beginning or end of each line/list entry. --- sconstruct | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sconstruct b/sconstruct index 52a70ce..f8976b6 100644 --- a/sconstruct +++ b/sconstruct @@ -30,19 +30,21 @@ def md2html(source, dest): for k, v in headerDic.items(): mdText = mdText.replace(k, v, 1) htmlText = markdown.markdown(mdText) + # Optimization: build resulting HTML text in one go instead of writing parts separately. + docText = "\n".join([ + "", + "" % lang, + "", + "" + "", + "", + "%s" % title, + "\n", + htmlText, + "\n" + ]) with codecs.open(dest, "w", "utf-8") as f: - f.write( - "\n" - + "\n" % lang - + "\n" - + "\n" - + "\n" - + "\n" - + "%s\n" % title - + "\n\n" - ) - f.write(htmlText) - f.write("\n\n") + f.write(docText) def mdTool(env): From e2b1d3ac991ee1c077b992c06ec1560404510b3c Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 02:06:09 -0700 Subject: [PATCH 129/362] SConstruct: explain that Flake8 F821 should be ignored as 'undefined' variables come from SCons. --- sconstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/sconstruct b/sconstruct index f8976b6..ab65f93 100644 --- a/sconstruct +++ b/sconstruct @@ -60,6 +60,7 @@ def mdTool(env): env['BUILDERS']['markdown'] = mdBuilder +# If using Flake8, F821 should be ignored as 'Variables' and friends come from SCons. vars = Variables() vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) From 219257837e60f34b7fb5ef47f427f0f96e99eaa1 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 09:46:52 -0700 Subject: [PATCH 130/362] Revert "BuildVars: restore lambda assignment (never, EVER change this line as indicated in the comment above)." This reverts commit 78500f74677c5c42f29240968a82752fd217fa26 based on comments from @Lukaszgo1 (lambda assignment is syntactically the same as function definition). --- buildVars.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index c3c853c..6a2f812 100644 --- a/buildVars.py +++ b/buildVars.py @@ -5,7 +5,8 @@ # Full getext (please don't change) -_ = lambda x: x # NOQA: E731 # Never, EVER change this line +def _(arg): + return arg # Add-on information variables From 2feb48596aed47807acdfa34087ae3775619abe9 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 09:48:31 -0700 Subject: [PATCH 131/362] BuildVars: add an explanation regarding Gettext call --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 6a2f812..612fedb 100644 --- a/buildVars.py +++ b/buildVars.py @@ -4,7 +4,7 @@ # Change this file instead of sconstruct or manifest files, whenever possible. -# Full getext (please don't change) +# Full getext def _(arg): return arg From f9a9503c106d4d5b86991d594fbb81d648d09a0e Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 26 Sep 2020 09:50:32 -0700 Subject: [PATCH 132/362] BuildVars: revert 'import os.path' based on comments by @Lukaszgo1. --- buildVars.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/buildVars.py b/buildVars.py index 612fedb..d813a82 100644 --- a/buildVars.py +++ b/buildVars.py @@ -39,10 +39,6 @@ def _(arg): "addon_updateChannel": None, } - -import os.path # NOQA - - # Define the python files that are the sources of your add-on. # You can use glob expressions here, they will be expanded. pythonSources = [] From 9191790460d9f737a4b4a4d29a4b5934102b4382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Sun, 27 Sep 2020 18:11:04 +0200 Subject: [PATCH 133/362] Sconstruct: Import SCons functions explicitly to avoid F821 warnings from Flake8 --- sconstruct | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index ab65f93..9d5a112 100644 --- a/sconstruct +++ b/sconstruct @@ -9,6 +9,13 @@ import os import os.path import zipfile import sys + +# While names imported below are available by default in every SConscript +# Linters aren't aware about them. +# To avoid Flake8 F821 warnings about them they are imported explicitly. +# When using other Scons functions please add them to the line below. +from SCons.Script import BoolVariable, Builder, Copy, Environment, Variables + sys.dont_write_bytecode = True # Bytecode should not be written for build vars module to keep the repository root folder clean. @@ -60,7 +67,6 @@ def mdTool(env): env['BUILDERS']['markdown'] = mdBuilder -# If using Flake8, F821 should be ignored as 'Variables' and friends come from SCons. vars = Variables() vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) From 1c4b070bfdc34376b1621908cbc497d8569aca2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Sun, 27 Sep 2020 18:20:01 +0200 Subject: [PATCH 134/362] buildVars: Explaing why "fakae" gettext function is needed. --- buildVars.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index d813a82..eb3aba0 100644 --- a/buildVars.py +++ b/buildVars.py @@ -4,7 +4,11 @@ # Change this file instead of sconstruct or manifest files, whenever possible. -# Full getext +# Since some strings in `addon_info` are translatable, +# we need to include them in the .po files. +# Gettext recognizes only strings given as parameters to the `_` function. +# To avoid initializing translations in this module we simply roll our own "fake" `_` function +# which returns whatever is given to it as an argument. def _(arg): return arg From 14bbff8aece398e16c53acf8aed21964ad9e4ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Sun, 27 Sep 2020 18:41:09 +0200 Subject: [PATCH 135/362] buildVars: Explain how to specify source files of the add-on using Glob expressions. --- buildVars.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index eb3aba0..01cd688 100644 --- a/buildVars.py +++ b/buildVars.py @@ -44,7 +44,13 @@ def _(arg): } # Define the python files that are the sources of your add-on. -# You can use glob expressions here, they will be expanded. +# You can either list every file (using ""/") as a path separator, +# or use glob expressions. +# For example to include all files with a ".py" extension from the "globalPlugins" dir of your add-on +# the list can be written as follows: +# pythonSources = ["addon/globalPlugins/*.py"] +# For more information on SCons Glob expressions please take a loog at: +# https://scons.org/doc/production/HTML/scons-user/apd.html pythonSources = [] # Files that contain strings for translation. Usually your python sources From 4b2f57b4ca4dc77c2dfc8222af18e7beb1784c7f Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 27 Sep 2020 10:15:25 -0700 Subject: [PATCH 136/362] BuildVars: log -> look --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 01cd688..7eb20c5 100644 --- a/buildVars.py +++ b/buildVars.py @@ -49,7 +49,7 @@ def _(arg): # For example to include all files with a ".py" extension from the "globalPlugins" dir of your add-on # the list can be written as follows: # pythonSources = ["addon/globalPlugins/*.py"] -# For more information on SCons Glob expressions please take a loog at: +# For more information on SCons Glob expressions please take a look at: # https://scons.org/doc/production/HTML/scons-user/apd.html pythonSources = [] From af9726cef9c2f517a8d74621ee0e5c816ab08751 Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Fri, 2 Oct 2020 13:52:30 +0200 Subject: [PATCH 137/362] Added baseLanguage variable to set the primary add-on language (useful if it's different from english). --- buildVars.py | 5 +++++ sconstruct | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 7eb20c5..c7f128c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -59,3 +59,8 @@ def _(arg): # Files that will be ignored when building the nvda-addon file # Paths are relative to the addon directory, not to the root directory of your addon sources. excludedFiles = [] + +# Base language for the NVDA add-on +# If the source code, add-on interface and readme file located in the root folder are written in a language other than english, modify this variable as appropriate. +# For example, set baseLanguage to "es" if your add-on is primarily in spanish +baseLanguage = "en" diff --git a/sconstruct b/sconstruct index 9d5a112..6859797 100644 --- a/sconstruct +++ b/sconstruct @@ -130,7 +130,7 @@ def createAddonHelp(dir): cssTarget = env.Command(cssPath, "style.css", Copy("$TARGET", "$SOURCE")) env.Depends(addon, cssTarget) if os.path.isfile("readme.md"): - readmePath = os.path.join(docsDir, "en", "readme.md") + readmePath = os.path.join(docsDir, buildVars.baseLanguage, "readme.md") readmeTarget = env.Command(readmePath, "readme.md", Copy("$TARGET", "$SOURCE")) env.Depends(addon, readmeTarget) From 8447748ee3dbb32b451b97034a1d313056cf2f49 Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Fri, 2 Oct 2020 13:53:49 +0200 Subject: [PATCH 138/362] Documentation: changed references from easy_install to pip --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 8eaf4fc..bbf01ba 100644 --- a/readme.md +++ b/readme.md @@ -24,9 +24,9 @@ This template provides the following features you can use to help NVDA add-on de You need the following software to use this code for your NVDA add-ons development: * a Python distribution (3.7 or later is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. -* Scons - [Website](http://www.scons.org/) - version 3.1.0 or greater. Install it using **easy_install** or grab an windows installer from the website. +* Scons - [Website](http://www.scons.org/) - version 3.1.0 or greater. Install it using **pip** or grab an windows installer from the website. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). -* Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `easy_install markdown`. +* Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `pip install markdown`. ## Usage From 6adc1dfd063625e0fea2d5e5a6e328009a9b261f Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Fri, 2 Oct 2020 13:54:52 +0200 Subject: [PATCH 139/362] All links included in the documentation are now https instead of http --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index bbf01ba..a8521a7 100644 --- a/readme.md +++ b/readme.md @@ -23,9 +23,9 @@ This template provides the following features you can use to help NVDA add-on de You need the following software to use this code for your NVDA add-ons development: -* a Python distribution (3.7 or later is recommended). Check the [Python Website](http://www.python.org) for Windows Installers. -* Scons - [Website](http://www.scons.org/) - version 3.1.0 or greater. Install it using **pip** or grab an windows installer from the website. -* GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](http://gnuwin32.sourceforge.net/downlinks/gettext.php). +* a Python distribution (3.7 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. +* Scons - [Website](https://www.scons.org/) - version 3.1.0 or greater. Install it using **pip** or grab an windows installer from the website. +* GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). * Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `pip install markdown`. ## Usage From c00e4fa632af3f5904a7fd1eb923355d295b458b Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Mon, 5 Oct 2020 19:50:17 +0200 Subject: [PATCH 140/362] BuildVars: fix comment length --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index c7f128c..c734085 100644 --- a/buildVars.py +++ b/buildVars.py @@ -61,6 +61,6 @@ def _(arg): excludedFiles = [] # Base language for the NVDA add-on -# If the source code, add-on interface and readme file located in the root folder are written in a language other than english, modify this variable as appropriate. +# If your add-on is written in a language other than english, modify this variable # For example, set baseLanguage to "es" if your add-on is primarily in spanish baseLanguage = "en" From 211189be6dc4f064d9058e89ef8471383ae974e1 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 17 Oct 2020 11:11:33 -0700 Subject: [PATCH 141/362] BuildVars: grammar and punctuation. --- buildVars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index c734085..7596a9f 100644 --- a/buildVars.py +++ b/buildVars.py @@ -61,6 +61,6 @@ def _(arg): excludedFiles = [] # Base language for the NVDA add-on -# If your add-on is written in a language other than english, modify this variable -# For example, set baseLanguage to "es" if your add-on is primarily in spanish +# If your add-on is written in a language other than english, modify this variable. +# For example, set baseLanguage to "es" if your add-on is primarily written in spanish. baseLanguage = "en" From 4d43f32c8bb648f641197042da753430913e7082 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 17 Oct 2020 11:21:45 -0700 Subject: [PATCH 142/362] Readme: add information on command-line switches (with a caution message). --- readme.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index a8521a7..69ad8d6 100644 --- a/readme.md +++ b/readme.md @@ -2,17 +2,18 @@ This package contains a basic template structure for NVDA add-on development, building, distribution and localization. For details about NVDA add-on development, please see the [NVDA Add-on Development Guide](https://github.com/nvdaaddons/DevGuide/wiki/NVDA-Add-on-Development-Guide). -The NVDA addon development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) +The NVDA add-on development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) -Copyright (C) 2012-2020 nvda addon team contributors. +Copyright (C) 2012-2020 NVDA Add-on team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. ## Features -This template provides the following features you can use to help NVDA add-on development: +This template provides the following features you can use during NVDA add-on development and packaging: -* Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py). +* Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py) or command-line interface. + * See packaging section for details on using command-line switches when packaging add-ons with custom version information. * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. See below for add-on manifest specification. * Compilation of gettext mo files before distribution, when needed. * To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. @@ -21,7 +22,7 @@ This template provides the following features you can use to help NVDA add-on de ## Requirements -You need the following software to use this code for your NVDA add-ons development: +You need the following software to use this code for your NVDA add-on development and packaging: * a Python distribution (3.7 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. * Scons - [Website](https://www.scons.org/) - version 3.1.0 or greater. Install it using **pip** or grab an windows installer from the website. @@ -63,6 +64,10 @@ An add-on manifest generated manually or via **buildVars.py** must include the f 1. Open a command line, change to the folder that has the **sconstruct** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. 2. You can further customize variables in the **buildVars.py** file. +3. You can also customize version and update channel information from command line by passing the following switches when running scons: + * version: add-on version string. + * channel: update channel (do not use this switch unless you know what you are doing). + * dev: suitable for development builds, names the add-on according to current date (yyyymmdd) and sets update channel to "dev". Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. From 5d18b6b3a163cb139b7c8cb8bc21b76db9857e77 Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Sun, 3 Jan 2021 17:51:55 +0100 Subject: [PATCH 143/362] Use baseLanguage variable also in scons clean command. Previously, instead of removing documentation for the chosen base language, english documentation was removed --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 6859797..fdb3722 100644 --- a/sconstruct +++ b/sconstruct @@ -229,4 +229,4 @@ env.Depends(manifest, "buildVars.py") env.Depends(addon, manifest) env.Default(addon) -env.Clean(addon, ['.sconsign.dblite', 'addon/doc/en/']) +env.Clean(addon, ['.sconsign.dblite', 'addon/doc/' + buildVars.baseLanguage + '/']) From db13cba79dea7825f87014e62cb845b6d2b3915f Mon Sep 17 00:00:00 2001 From: Jose Manuel Delicado Date: Sun, 3 Jan 2021 18:02:23 +0100 Subject: [PATCH 144/362] Add-on documentation titles are now properly translated before generating HTML files. Contribution made by @paulber19 --- sconstruct | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 6859797..15ea3c0 100644 --- a/sconstruct +++ b/sconstruct @@ -25,8 +25,17 @@ import buildVars # NOQA: E402 def md2html(source, dest): import markdown lang = os.path.basename(os.path.dirname(source)).replace('_', '-') + localeLang = os.path.basename(os.path.dirname(source)) + try: + if sys.version_info.major == 2: + _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).ugettext + else: + _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).gettext + summary = _(buildVars.addon_info["addon_summary"]) + except: + summary = buildVars.addon_info["addon_summary"] title = "{addonSummary} {addonVersion}".format( - addonSummary=buildVars.addon_info["addon_summary"], addonVersion=buildVars.addon_info["addon_version"] + addonSummary=summary, addonVersion=buildVars.addon_info["addon_version"] ) headerDic = { "[[!meta title=\"": "# ", From 13b42d14884d632ef3258b1ac383910e0f433d02 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 11 Jan 2021 13:44:54 -0800 Subject: [PATCH 145/362] SConstruct: include tables extension. Include Markdown tables extension (requested by an author). Note that this is a temporary commit for Add-on Template 2020.4 and will be replaced by an extensions list in Template 2021.1. --- sconstruct | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 345d77a..33425ae 100644 --- a/sconstruct +++ b/sconstruct @@ -24,6 +24,9 @@ import buildVars # NOQA: E402 def md2html(source, dest): import markdown + # Temp: to be replaced by an extensions list in spring 2021. + import markdown.extensions.tables + mdTable = markdown.extensions.tables.TableExtension() lang = os.path.basename(os.path.dirname(source)).replace('_', '-') localeLang = os.path.basename(os.path.dirname(source)) try: @@ -45,7 +48,7 @@ def md2html(source, dest): mdText = f.read() for k, v in headerDic.items(): mdText = mdText.replace(k, v, 1) - htmlText = markdown.markdown(mdText) + htmlText = markdown.markdown(mdText, extensions=[mdTable]) # Optimization: build resulting HTML text in one go instead of writing parts separately. docText = "\n".join([ "", From b1e6fa86bb738c147940a3b631de82e205181145 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 11 Jan 2021 13:52:41 -0800 Subject: [PATCH 146/362] BuildVars: add markdownExteisions list. Most add-on documentation files do not require Markdown extensions such as tables. For those that do, a list of Markdown extensions (a string list) can be passed into SConstruct via buildVars to enable support for things usch as tables. --- buildVars.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/buildVars.py b/buildVars.py index 7596a9f..bfa621c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -64,3 +64,10 @@ def _(arg): # If your add-on is written in a language other than english, modify this variable. # For example, set baseLanguage to "es" if your add-on is primarily written in spanish. baseLanguage = "en" + +# Markdown extensions for add-on documentation +# Most add-ons do not require additional Markdown extensions. +# If you need to add support for markup such as tables, fill out the below list. +# Extensions string must be of the form "markdown.extensions.extensionName:extensionClass" +# e.g. markdown.extensions.tables:TableExtension to add tables. +markdownExtensions = [] From e15ca18c4a50d807c96826ad3a6577deaab83bd1 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 11 Jan 2021 20:38:24 -0800 Subject: [PATCH 147/362] BuildVars: edit Markdown extensions list comment (className is not needed). --- buildVars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index bfa621c..5a40140 100644 --- a/buildVars.py +++ b/buildVars.py @@ -68,6 +68,6 @@ def _(arg): # Markdown extensions for add-on documentation # Most add-ons do not require additional Markdown extensions. # If you need to add support for markup such as tables, fill out the below list. -# Extensions string must be of the form "markdown.extensions.extensionName:extensionClass" -# e.g. markdown.extensions.tables:TableExtension to add tables. +# Extensions string must be of the form "markdown.extensions.extensionName" +# e.g. markdown.extensions.tables to add tables. markdownExtensions = [] From f9ed8fae82740ec444774fd8699c75ee78b888a6 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 3 Mar 2021 15:30:47 -0800 Subject: [PATCH 148/362] Readme: update copyright year --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 69ad8d6..ddceb4b 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ This package contains a basic template structure for NVDA add-on development, bu For details about NVDA add-on development, please see the [NVDA Add-on Development Guide](https://github.com/nvdaaddons/DevGuide/wiki/NVDA-Add-on-Development-Guide). The NVDA add-on development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) -Copyright (C) 2012-2020 NVDA Add-on team contributors. +Copyright (C) 2012-2021 NVDA Add-on team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. From fa9efa1d644b34fd14f41baf94725a640ac73178 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 3 Mar 2021 15:38:23 -0800 Subject: [PATCH 149/362] Readme: direct users to use PIP when installing SCons and Markdown, update minimum version. --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index ddceb4b..74cc3f0 100644 --- a/readme.md +++ b/readme.md @@ -25,13 +25,13 @@ This template provides the following features you can use during NVDA add-on dev You need the following software to use this code for your NVDA add-on development and packaging: * a Python distribution (3.7 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. -* Scons - [Website](https://www.scons.org/) - version 3.1.0 or greater. Install it using **pip** or grab an windows installer from the website. +* Scons - [Website](https://www.scons.org/) - version 3.1.0 or later. You can instlal it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). -* Markdown-2.0.1 or greater, if you want to convert documentation files to HTML documents. You can [Download Markdown-2.0.1 installer for Windows](https://pypi.python.org/pypi/Markdown/2.0.1) or get it using `pip install markdown`. +* Markdown 3.1.0 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. ## Usage -### To create a new NVDA add-on, taking advantage of this template: +### To create a new NVDA add-on using this template: 1. Create an empty folder to hold the files for your add-on. 2. Copy the **site_scons** folder, and the following files, into your new empty folder: **buildVars.py**, **manifest.ini.tpl**, **manifest-translated.ini.tpl**, **sconstruct**, **.gitignore**, and **.gitattributes** From 2666b7c4f8b2b659f6776f3f756ce125b310d45d Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 3 Mar 2021 15:40:02 -0800 Subject: [PATCH 150/362] SConstruct: update copyright year --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 33425ae..0a95599 100644 --- a/sconstruct +++ b/sconstruct @@ -1,5 +1,5 @@ # NVDA add-on template SCONSTRUCT file -# Copyright (C) 2012-2020 Rui Batista, Noelia Martinez, Joseph Lee +# Copyright (C) 2012-2021 Rui Batista, Noelia Martinez, Joseph Lee # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. From c0c882b5a5ac4636fea9227aab94326aa19d29c1 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 3 Mar 2021 15:50:10 -0800 Subject: [PATCH 151/362] SConstruct: remove Python 2 support. Python 3.7 or later is now required to use the add-on template, therefore remove last remnants of Python 2 (sys.version check). --- sconstruct | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sconstruct b/sconstruct index 0a95599..dc5ce35 100644 --- a/sconstruct +++ b/sconstruct @@ -30,10 +30,7 @@ def md2html(source, dest): lang = os.path.basename(os.path.dirname(source)).replace('_', '-') localeLang = os.path.basename(os.path.dirname(source)) try: - if sys.version_info.major == 2: - _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).ugettext - else: - _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).gettext + _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).gettext summary = _(buildVars.addon_info["addon_summary"]) except: summary = buildVars.addon_info["addon_summary"] @@ -172,11 +169,7 @@ def generateManifest(source, dest): def generateTranslatedManifest(source, language, out): - # No ugettext in Python 3. - if sys.version_info.major == 2: - _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).ugettext - else: - _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).gettext + _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).gettext vars = {} for var in ("addon_summary", "addon_description"): vars[var] = _(buildVars.addon_info[var]) From 22d6eeba1a6f2095157cf821daf26efe94b4987b Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 3 Mar 2021 16:12:10 -0800 Subject: [PATCH 152/362] SConstruct: ecetp -> except Exception (Flake8 E722 lint) --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index dc5ce35..7f3e6e1 100644 --- a/sconstruct +++ b/sconstruct @@ -32,7 +32,7 @@ def md2html(source, dest): try: _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).gettext summary = _(buildVars.addon_info["addon_summary"]) - except: + except Exception: summary = buildVars.addon_info["addon_summary"] title = "{addonSummary} {addonVersion}".format( addonSummary=summary, addonVersion=buildVars.addon_info["addon_version"] From 4949c1bb8e0ddd4b13c5cdc5d4f9e6019854b996 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 3 Mar 2021 17:37:37 -0800 Subject: [PATCH 153/362] Build Vars: clarify Markdown extensions list format --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 5a40140..30dea3a 100644 --- a/buildVars.py +++ b/buildVars.py @@ -69,5 +69,5 @@ def _(arg): # Most add-ons do not require additional Markdown extensions. # If you need to add support for markup such as tables, fill out the below list. # Extensions string must be of the form "markdown.extensions.extensionName" -# e.g. markdown.extensions.tables to add tables. +# e.g. "markdown.extensions.tables" to add tables. markdownExtensions = [] From c94190f1f430f8fb448228e6cc570bf612be7f0a Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 3 Mar 2021 17:46:08 -0800 Subject: [PATCH 154/362] SConstruct: use Markdown extensions list defined in build vars. Read Markdown extensions list from build vars. This allows other extensions besides tables to be used when generating documentation. --- sconstruct | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index 7f3e6e1..ab61654 100644 --- a/sconstruct +++ b/sconstruct @@ -24,9 +24,8 @@ import buildVars # NOQA: E402 def md2html(source, dest): import markdown - # Temp: to be replaced by an extensions list in spring 2021. - import markdown.extensions.tables - mdTable = markdown.extensions.tables.TableExtension() + # Use extensions if defined. + mdExtensions = buildVars.markdownExtensions lang = os.path.basename(os.path.dirname(source)).replace('_', '-') localeLang = os.path.basename(os.path.dirname(source)) try: @@ -45,7 +44,7 @@ def md2html(source, dest): mdText = f.read() for k, v in headerDic.items(): mdText = mdText.replace(k, v, 1) - htmlText = markdown.markdown(mdText, extensions=[mdTable]) + htmlText = markdown.markdown(mdText, extensions=mdExtensions) # Optimization: build resulting HTML text in one go instead of writing parts separately. docText = "\n".join([ "", From da6cd613b826073bad1341147bb6a7e6b3f829ae Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 19 May 2022 07:18:00 -0700 Subject: [PATCH 155/362] Readme: SCons 4.3.0, Markdown 3.3.0 or later --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 74cc3f0..ce90ea5 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ This package contains a basic template structure for NVDA add-on development, bu For details about NVDA add-on development, please see the [NVDA Add-on Development Guide](https://github.com/nvdaaddons/DevGuide/wiki/NVDA-Add-on-Development-Guide). The NVDA add-on development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) -Copyright (C) 2012-2021 NVDA Add-on team contributors. +Copyright (C) 2012-2022 NVDA Add-on team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. @@ -25,9 +25,9 @@ This template provides the following features you can use during NVDA add-on dev You need the following software to use this code for your NVDA add-on development and packaging: * a Python distribution (3.7 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. -* Scons - [Website](https://www.scons.org/) - version 3.1.0 or later. You can instlal it via PIP. +* Scons - [Website](https://www.scons.org/) - version 4.3.0 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). -* Markdown 3.1.0 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. +* Markdown 3.3.0 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. ## Usage From 30be76875ba3437376aeaad161a32ea2c0dd4fb4 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 19 May 2022 07:18:41 -0700 Subject: [PATCH 156/362] SConstruct: update copyright year --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index ab61654..103a74c 100644 --- a/sconstruct +++ b/sconstruct @@ -1,5 +1,5 @@ # NVDA add-on template SCONSTRUCT file -# Copyright (C) 2012-2021 Rui Batista, Noelia Martinez, Joseph Lee +# Copyright (C) 2012-2022 Rui Batista, Noelia Martinez, Joseph Lee # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. From 15322394b738b8ccf4bceed6ca869379a66e0805 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 19 May 2022 07:31:05 -0700 Subject: [PATCH 157/362] Flake8 (additional tools): add a basic Flake8 config file. Provide a basic lake8 config file based on NVDA o add-on authors can perform lints. --- flake8.ini | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 flake8.ini diff --git a/flake8.ini b/flake8.ini new file mode 100644 index 0000000..8253925 --- /dev/null +++ b/flake8.ini @@ -0,0 +1,43 @@ +# Custom Flake8 configuration for community add-on template +# Based on NVDA's Flake8 configuration with modifications for the basic add-on template (edited by Joseph Lee) + +[flake8] + +# Plugins +use-flake8-tabs = True +# Not all checks are replaced by flake8-tabs, however, pycodestyle is still not compatible with tabs. +use-pycodestyle-indent = False +continuation-style = hanging +## The following are replaced by flake8-tabs plugin, reported as ET codes rather than E codes. +# E121, E122, E123, E126, E127, E128, +## The following (all disabled) are not replaced by flake8-tabs, +# E124 - Requires mixing spaces and tabs: Closing bracket does not match visual indentation. +# E125 - Does not take tabs into consideration: Continuation line with same indent as next logical line. +# E129 - Requires mixing spaces and tabs: Visually indented line with same indent as next logical line +# E131 - Requires mixing spaces and tabs: Continuation line unaligned for hanging indent +# E133 - Our preference handled by ET126: Closing bracket is missing indentation + + +# Reporting +statistics = True +doctests = True +show-source = True + +# Options +max-complexity = 15 +max-line-length = 110 +# Final bracket should match indentation of the start of the line of the opening bracket +hang-closing = False + +ignore = + ET113, # use of alignment as indentation, but option continuation-style=hanging does not permit this + W191, # indentation contains tabs + W503, # line break before binary operator. We want W504(line break after binary operator) + +builtins = # inform flake8 about functions we consider built-in. + _, # translation lookup + pgettext, # translation lookup + +exclude = # don't bother looking in the following subdirectories / files. + .git, + __pycache__, From 1fb8f6e945aa35b065fa5869da8f7a9ead6c9704 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 19 May 2022 07:31:45 -0700 Subject: [PATCH 158/362] Readme: add notes on additional tools such as Flake8 config ifle --- readme.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index ce90ea5..dab736b 100644 --- a/readme.md +++ b/readme.md @@ -20,6 +20,10 @@ This template provides the following features you can use during NVDA add-on dev * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. * Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. +In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): + +* Flake8 (flake8.ini): a base configuration file for Flake8 linting tool based on NVDA's own Flake8 configuration file. + ## Requirements You need the following software to use this code for your NVDA add-on development and packaging: @@ -69,6 +73,14 @@ An add-on manifest generated manually or via **buildVars.py** must include the f * channel: update channel (do not use this switch unless you know what you are doing). * dev: suitable for development builds, names the add-on according to current date (yyyymmdd) and sets update channel to "dev". -Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs. +### Additional tools + +The template includes configuration files for use with additional tools such as linters. These include: + +* Flake8 (flake8.ini): a Python code linter (3.7.9 or later, can be installed with PIP). + +Read the documentation for the tools you wish to use when building and developing add-ons. + +Note that this template only provides a basic add-on structure and build infrastructure. You may need to adapt it for your specific needs such as using additional tools. If you have any issues please use the NVDA addon list mentioned above. From 8b50935d906fdc3c6d42fe21621d81fb119ebeb6 Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 11 Oct 2022 15:58:34 +0300 Subject: [PATCH 159/362] add workflow --- .github/workflows/build_addon.yml | 63 +++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/build_addon.yml diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml new file mode 100644 index 0000000..f146c07 --- /dev/null +++ b/.github/workflows/build_addon.yml @@ -0,0 +1,63 @@ +name: build addon + +on: + push: + tags: ["*"] + branches: [ main , master ] + + pull_request: + branches: [ main, master ] + + workflow_dispatch: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.9 + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip wheel + pip install -r requirements.txt + sudo apt-get update -y + sudo apt-get install -y gettext + + - name: Code checks + run: export SKIP=no-commit-to-branch; pre-commit run --all + + - name: building addon + run: scons + + - uses: actions/upload-artifact@v3 + with: + name: packaged_addon + path: ./*.nvda-addon + + upload_release: + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/tags/') }} + needs: ["build"] + steps: + - uses: actions/checkout@v3 + - name: download releases files + uses: actions/download-artifact@v3 + - name: Display structure of downloaded files + run: ls -R + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: packaged_addon/*.nvda-addon + fail_on_unmatched_files: true + prerelease: ${{ contains(github.ref, '-') }} From 604eae8226f58e53e84f47615726d6b12519b468 Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 11 Oct 2022 15:58:59 +0300 Subject: [PATCH 160/362] add pre-commit --- .pre-commit-config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..dd7a9d6 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: check-ast + - id: check-case-conflict + - id: check-yaml From 61eaa45b20eaa682f584f1340e7224ce6b4875cc Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 11 Oct 2022 15:59:34 +0300 Subject: [PATCH 161/362] add information about GH Actions --- readme.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/readme.md b/readme.md index dab736b..8615296 100644 --- a/readme.md +++ b/readme.md @@ -8,12 +8,24 @@ Copyright (C) 2012-2022 NVDA Add-on team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. + + +[alekssamos](https://github.com/alekssamos/) added automatic package of add-ons through Github Actions. + +For details about Github Actions please see the [Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). + +Copyright (C) 2022 alekssamos + + ## Features This template provides the following features you can use during NVDA add-on development and packaging: * Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py) or command-line interface. * See packaging section for details on using command-line switches when packaging add-ons with custom version information. + * This process will happen automatically when you commit to the main branch, when receiving a pull request, and there is also the possibility of manual launch. + * If you have created a tag (E.G.: `git tag v1.0 && git push --tag`), then a release will be automatically created and the add-on file will be uploaded as an asset. + * Otherwise, with normal commits or with manual startup, you can download the artifacts from the Actions page of your repository. * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. See below for add-on manifest specification. * Compilation of gettext mo files before distribution, when needed. * To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. From 9f70adb8af32b290d0a82a635677e4e336be095e Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 11 Oct 2022 22:45:32 -0700 Subject: [PATCH 162/362] BuidVars: add some fields from NV Access add-on datastore. Re #22. NV Access add-on store uses JSON to represent add-on release data. Therefore add add-on license, license URL, and source (repository) URL, used when generating add-on store JSON file (there are other fields such as publisher and hash but they must be defined after JSON is created). --- buildVars.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/buildVars.py b/buildVars.py index 30dea3a..73ae47e 100644 --- a/buildVars.py +++ b/buildVars.py @@ -31,6 +31,8 @@ def _(arg): "addon_author": "name ", # URL for the add-on documentation support "addon_url": None, + # URL for the add-on repository where the source code can be found + "addon_sourceURL": None, # Documentation file name "addon_docFileName": "readme.html", # Minimum NVDA version supported (e.g. "2018.3.0", minor version is optional) @@ -41,6 +43,10 @@ def _(arg): # and for development releases, use "dev".) # Do not change unless you know what you are doing! "addon_updateChannel": None, + # Add-on license such as GPL 2 + "addon_license": None, + # URL for the license document the ad-on is licensed under + "addon_licenseURL": None, } # Define the python files that are the sources of your add-on. From 478dfb52f987d87671d4548d17ab34679302dd92 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 11 Oct 2022 22:51:22 -0700 Subject: [PATCH 163/362] SConstruct: define a json generator function. Re #22. Define a json generator that takes the path of an add-on bundle and builds NV Access add-on store json entry. --- sconstruct | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/sconstruct b/sconstruct index 103a74c..f5e4ec9 100644 --- a/sconstruct +++ b/sconstruct @@ -158,6 +158,59 @@ def createAddonBundleFromPath(path, dest): return dest +def createAddonStoreJson(bundle): + """Creates add-on store JSON file from an add-on package and manifest data.""" + import json + import hashlib + jsonFilename = f'{buildVars.addon_info["addon_name"]}-{buildVars.addon_info["addon_version"]}.json' + print('Generating % s' % jsonFilename) + sha256 = hashlib.sha256() + with open(bundle,"rb") as f: + for byte_block in iter(lambda: f.read(65536),b""): + sha256.update(byte_block) + hashValue = sha256.hexdigest() + minimumNVDAVersion = buildVars.addon_info["addon_minimumNVDAVersion"].split(".") + minMajor, minMinor = minimumNVDAVersion[:2] + minPatch = minimumNVDAVersion[-1] if len(minimumNVDAVersion) == 3 else "0" + lastTestedNVDAVersion = buildVars.addon_info["addon_lastTestedNVDAVersion"].split(".") + lastTestedMajor, lastTestedMinor = lastTestedNVDAVersion[:2] + lastTestedPatch = lastTestedNVDAVersion[-1] if len(lastTestedNVDAVersion) == 3 else "0" + channel = buildVars.addon_info["addon_updateChannel"] + if channel is None: + channel = "stable" + addonStoreEntry = { + "addonId": buildVars.addon_info["addon_name"], + "displayName": buildVars.addon_info["addon_summary"], + "URL": "", + "description": buildVars.addon_info["addon_description"], + "sha256": hashValue, + "homepage": buildVars.addon_info["addon_url"], + "addonVersionName": buildVars.addon_info["addon_version"], + "addonVersionNumber": { + "major": 0, + "minor": 0, + "patch": 0 + }, + "minNVDAVersion": { + "major": int(minMajor), + "minor": int(minMinor), + "patch": int(minPatch) + }, + "lastTestedVersion": { + "major": int(lastTestedMajor), + "minor": int(lastTestedMinor), + "patch": int(lastTestedPatch) + }, + "channel": channel, + "publisher": "", + "sourceURL": buildVars.addon_info["addon_sourceURL"], + "license": buildVars.addon_info["addon_license"], + "licenseURL": buildVars.addon_info["addon_licenseURL"], + } + with open(jsonFilename, "w") as addonStoreJson: + json.dump(addonStoreEntry, addonStoreJson, indent="\t") + + def generateManifest(source, dest): addon_info = buildVars.addon_info with codecs.open(source, "r", "utf-8") as f: From ad25683a9f7f1d399167c62b4e44105ebf4d4e2a Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 11 Oct 2022 22:54:16 -0700 Subject: [PATCH 164/362] SConstruct: call json generaor after creating dd-on bundle. Re #22. Call json generator after building add-on package for submission to NV Access add-on store. --- sconstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/sconstruct b/sconstruct index f5e4ec9..7aa4c63 100644 --- a/sconstruct +++ b/sconstruct @@ -155,6 +155,7 @@ def createAddonBundleFromPath(path, dest): absPath = os.path.join(dir, filename) if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle) + createAddonStoreJson(dest) return dest From 3188020e8833547840c50f2913788158135f31b8 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 11 Oct 2022 23:36:30 -0700 Subject: [PATCH 165/362] SConstruct: Flake8 - add whitespace --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 7aa4c63..15b1702 100644 --- a/sconstruct +++ b/sconstruct @@ -166,8 +166,8 @@ def createAddonStoreJson(bundle): jsonFilename = f'{buildVars.addon_info["addon_name"]}-{buildVars.addon_info["addon_version"]}.json' print('Generating % s' % jsonFilename) sha256 = hashlib.sha256() - with open(bundle,"rb") as f: - for byte_block in iter(lambda: f.read(65536),b""): + with open(bundle, "rb") as f: + for byte_block in iter(lambda: f.read(65536), b""): sha256.update(byte_block) hashValue = sha256.hexdigest() minimumNVDAVersion = buildVars.addon_info["addon_minimumNVDAVersion"].split(".") From c398ca4e7eaac4c9fa84b6c6bc9329010dc8f56a Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 12 Oct 2022 10:35:23 -0700 Subject: [PATCH 166/362] GitHub Actions: comment out building on main/master branch to avoid uid fialure for the add-on template --- .github/workflows/build_addon.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index f146c07..9b97cd9 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -3,7 +3,8 @@ name: build addon on: push: tags: ["*"] - branches: [ main , master ] + # To build on main/master branch, uncomment the following line: + # branches: [ main , master ] pull_request: branches: [ main, master ] From 6e8a02da88941327f951c49c87bec1b9a8b31cd8 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 12 Oct 2022 10:38:54 -0700 Subject: [PATCH 167/362] Readme: edit GitHub Actions line on main/master branch push --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8615296..1954ca7 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,8 @@ This template provides the following features you can use during NVDA add-on dev * Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py) or command-line interface. * See packaging section for details on using command-line switches when packaging add-ons with custom version information. - * This process will happen automatically when you commit to the main branch, when receiving a pull request, and there is also the possibility of manual launch. + * This process will happen automatically when receiving a pull request, and there is also the possibility of manual launch. + * To let the workflow run automatically when pushing to main or master (development) branch, remove the comment for branches line in GitHub Actions (.github/workflow/build_addon.yml). * If you have created a tag (E.G.: `git tag v1.0 && git push --tag`), then a release will be automatically created and the add-on file will be uploaded as an asset. * Otherwise, with normal commits or with manual startup, you can download the artifacts from the Actions page of your repository. * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. See below for add-on manifest specification. From 89db11eb3e8dd196428bf6a072eaab8f06ac5595 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 12 Oct 2022 10:47:36 -0700 Subject: [PATCH 168/362] Readme: document additional build vars fields such as license --- readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/readme.md b/readme.md index 1954ca7..ececbba 100644 --- a/readme.md +++ b/readme.md @@ -72,6 +72,12 @@ An add-on manifest generated manually or via **buildVars.py** must include the f * lastTestedNVDAVersion (year.major or year.major.minor): the latest or last tested version of NVDA the add-on is said to be compatible with (e.g. 2020.3). Add-on authors are expected to declare this value after testing add-ons with the version of NVDA specified. * addon_updateChannel (string or None): the update channel for the add-on release. +In addition, the following information must be filled out (not used in the manifest): + +* sourceURL (string): repository URL for the add-on source code. +* license (string): the license of the add-on and its source code. +* licenseURL: the URL for the license file. + ### To manage documentation files for your addon: 1. Copy the **readme.md** file for your add-on to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. From cf3995b335496e84495ff77eeba28c874cb09c28 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Fri, 30 Dec 2022 23:56:27 -0800 Subject: [PATCH 169/362] Update copyright year --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 15b1702..e0752c3 100644 --- a/sconstruct +++ b/sconstruct @@ -1,5 +1,5 @@ # NVDA add-on template SCONSTRUCT file -# Copyright (C) 2012-2022 Rui Batista, Noelia Martinez, Joseph Lee +# Copyright (C) 2012-2023 Rui Batista, Noelia Martinez, Joseph Lee # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. From 895bfd38c2fc4c6970f90c36c60973185bc03fc9 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 31 Dec 2022 00:01:47 -0800 Subject: [PATCH 170/362] SConstruct: add 'versionNumber' argument. Add 'versionNumber' as a command-line argument specifying three integers: major.minor.patch (in this exact format). This is used when submitting add-ons to NV Access datastore and the value is used to fill in 'version number' field in the resulting json file. By default it is set to 0.0.0. --- sconstruct | 1 + 1 file changed, 1 insertion(+) diff --git a/sconstruct b/sconstruct index e0752c3..231f5a4 100644 --- a/sconstruct +++ b/sconstruct @@ -77,6 +77,7 @@ def mdTool(env): vars = Variables() vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) +vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0", validateVersionNumber) vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) From 1b16393440f77a3be16ee10e45c869975dfd7f01 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 31 Dec 2022 00:04:06 -0800 Subject: [PATCH 171/362] SConstruct: validate version number string. Make sure version number passed in is of the form major (int).minor (int).patch (int), otherwise raise a value eror. --- sconstruct | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sconstruct b/sconstruct index 231f5a4..219eff6 100644 --- a/sconstruct +++ b/sconstruct @@ -75,6 +75,18 @@ def mdTool(env): env['BUILDERS']['markdown'] = mdBuilder +def validateVersionNumber(key, val, env): + # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. + # Ignore all this if version number is not specified, in which case json generator will validate this information. + if val == "0.0.0": + return + versionNumber = val.split(".") + if len(versionNumber) < 3: + raise ValueError("versionNumber must have three parts (major.minor.patch)") + if not all([part.isnumeric() for part in versionNumber]): + raise ValueError("versionNumber (major.minor.patch) must be integers") + + vars = Variables() vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0", validateVersionNumber) From 83a81310d48aa2ff416f0bd1deb4271c7f50c019 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 31 Dec 2022 00:13:32 -0800 Subject: [PATCH 172/362] SConstruct/json generator: fill in add-on version major.minor.patch based on version number command-line argument. If 'versionNumber' command-line argument is specified, use it to fill in add-on version major.minor.patch. otherwise resort to add-on version as defined in buildVars unless that causes errors. --- sconstruct | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index 219eff6..d597fb5 100644 --- a/sconstruct +++ b/sconstruct @@ -176,7 +176,23 @@ def createAddonStoreJson(bundle): """Creates add-on store JSON file from an add-on package and manifest data.""" import json import hashlib - jsonFilename = f'{buildVars.addon_info["addon_name"]}-{buildVars.addon_info["addon_version"]}.json' + # Set different json file names and version number properties based on version number parsing results. + if env["versionNumber"] == "0.0.0": + env["versionNumber"] = buildVars.addon_info["addon_version"] + versionNumberParsed = env["versionNumber"].split(".") + if all([part.isnumeric() for part in versionNumberParsed]): + if len(versionNumberParsed) == 1: + versionNumberParsed += ["0", "0"] + elif len(versionNumberParsed) == 2: + versionNumberParsed.append("0") + else: + versionNumberParsed = [] + if len(versionNumberParsed): + major, minor, patch = [int(part) for part in versionNumberParsed] + jsonFilename = f'{buildVars.addon_info["addon_name"]}-{major}.{minor}.{patch}.json' + else: + jsonFilename = f'{buildVars.addon_info["addon_name"]}-{buildVars.addon_info["addon_version"]}.json' + major, minor, patch = 0, 0, 0 print('Generating % s' % jsonFilename) sha256 = hashlib.sha256() with open(bundle, "rb") as f: @@ -201,9 +217,9 @@ def createAddonStoreJson(bundle): "homepage": buildVars.addon_info["addon_url"], "addonVersionName": buildVars.addon_info["addon_version"], "addonVersionNumber": { - "major": 0, - "minor": 0, - "patch": 0 + "major": major, + "minor": minor, + "patch": patch }, "minNVDAVersion": { "major": int(minMajor), From 541d856a29eff9715766e53acde6a0840f127059 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 31 Dec 2022 00:18:31 -0800 Subject: [PATCH 173/362] SConstruct (Flake8 E501): shorten comment --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index d597fb5..8c04985 100644 --- a/sconstruct +++ b/sconstruct @@ -77,7 +77,7 @@ def mdTool(env): def validateVersionNumber(key, val, env): # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. - # Ignore all this if version number is not specified, in which case json generator will validate this information. + # Ignore all this if version number is not specified, in which case json generator will validate this info. if val == "0.0.0": return versionNumber = val.split(".") From 9c02809bea3b1a233339a0dacdd4301cf3f21050 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 31 Dec 2022 00:22:06 -0800 Subject: [PATCH 174/362] Readme: document versionNumber argument --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index ececbba..930caa1 100644 --- a/readme.md +++ b/readme.md @@ -89,6 +89,7 @@ In addition, the following information must be filled out (not used in the manif 2. You can further customize variables in the **buildVars.py** file. 3. You can also customize version and update channel information from command line by passing the following switches when running scons: * version: add-on version string. + * versionNumber: add-on version number of the form major.minor.patch (all integers) * channel: update channel (do not use this switch unless you know what you are doing). * dev: suitable for development builds, names the add-on according to current date (yyyymmdd) and sets update channel to "dev". From f035537164ce4f5acc5596873338645fe239356b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 4 Feb 2023 12:59:21 +0100 Subject: [PATCH 175/362] Add workspace configuration for VS Code --- .vscode/extensions.json | 12 ++++++++++++ .vscode/settings.json | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..75fa7aa --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,12 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "ms-python.python", + "ms-python.vscode-pylance", + "redhat.vscode-yaml" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7c58677 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,25 @@ +{ + "editor.accessibilitySupport": "on", + "python.linting.enabled": true, + "python.linting.maxNumberOfProblems": 10000, + "python.linting.flake8Args": [ + "--config=flake8.ini" + ], + "python.linting.flake8Enabled": true, + "python.linting.pylintEnabled": false, + "python.autoComplete.extraPaths": [ + "../nvda/source", + "../nvda/miscDeps/python" + ], + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "editor.insertSpaces": false, + "python.analysis.diagnosticSeverityOverrides": { + "reportUndefinedVariable": "none" + }, + "python.analysis.extraPaths": [ + "../nvda/source", + "../nvda/miscDeps/python" + ], + "python.defaultInterpreterPath": "../nvda/.venv/scripts/python.exe" +} From 20475bb4bcb140aafd5f2facf1923e0609626b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 4 Feb 2023 13:29:28 +0100 Subject: [PATCH 176/362] Update readme --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 930caa1..9f46f7d 100644 --- a/readme.md +++ b/readme.md @@ -36,6 +36,10 @@ This template provides the following features you can use during NVDA add-on dev In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): * Flake8 (flake8.ini): a base configuration file for Flake8 linting tool based on NVDA's own Flake8 configuration file. +* Configuration for VS Code. It requires NVDA`s repo at the same level that add-on repos, with prepared source code (`scons source`). + * Press `control+shift+m`after saving a file to search for problems. + * Use arrow and tab keys for the autocompletion feature. + * Press `control+shift+p`to open the commands palette and search for recommended extensions to install or check if they are installed. ## Requirements From a9968a4e155ce05048546c3728d9ee91a32ae066 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 4 Feb 2023 08:01:49 -0800 Subject: [PATCH 177/362] SConstruct: handle minimum and last teted NVDA versions being None. Sometimes minimum and last tested versions can be None, causing attribute error to be thrown when trying to split major, minor, patch. Therefore set tem to 0.0.0 if these values are none. --- sconstruct | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 8c04985..5f374bf 100644 --- a/sconstruct +++ b/sconstruct @@ -199,10 +199,16 @@ def createAddonStoreJson(bundle): for byte_block in iter(lambda: f.read(65536), b""): sha256.update(byte_block) hashValue = sha256.hexdigest() - minimumNVDAVersion = buildVars.addon_info["addon_minimumNVDAVersion"].split(".") + try: + minimumNVDAVersion = buildVars.addon_info["addon_minimumNVDAVersion"].split(".") + except AttributeError: + minimumNVDAVersion = [0, 0, 0] minMajor, minMinor = minimumNVDAVersion[:2] minPatch = minimumNVDAVersion[-1] if len(minimumNVDAVersion) == 3 else "0" - lastTestedNVDAVersion = buildVars.addon_info["addon_lastTestedNVDAVersion"].split(".") + try: + lastTestedNVDAVersion = buildVars.addon_info["addon_lastTestedNVDAVersion"].split(".") + except AttributeError: + lastTestedNVDAVersion = [0, 0, 0] lastTestedMajor, lastTestedMinor = lastTestedNVDAVersion[:2] lastTestedPatch = lastTestedNVDAVersion[-1] if len(lastTestedNVDAVersion) == 3 else "0" channel = buildVars.addon_info["addon_updateChannel"] From 07c8859abee2906ea6d50229c9cb0a7251d61278 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 28 Feb 2023 13:44:50 -0800 Subject: [PATCH 178/362] SConstruct: for dev biuds, default to YYYYMMDD.0.0 for version number. Add-on store submission: for default dev builds, use YYYYMMDD.0.0 as version number to follow precedence established by NV Access. --- sconstruct | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 5f374bf..d22756e 100644 --- a/sconstruct +++ b/sconstruct @@ -100,7 +100,9 @@ if env["dev"]: import datetime buildDate = datetime.datetime.now() year, month, day = str(buildDate.year), str(buildDate.month), str(buildDate.day) - env["addon_version"] = "".join([year, month.zfill(2), day.zfill(2), "-dev"]) + versionTimestamp = "".join([year, month.zfill(2), day.zfill(2)]) + env["addon_version"] = f"{versionTimestamp}-dev" + env["versionNumber"] = f"{versionTimestamp}.0.0" env["channel"] = "dev" elif env["version"] is not None: env["addon_version"] = env["version"] From b84938a626e63640da974d95549070270228bd26 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 28 Feb 2023 19:46:54 -0800 Subject: [PATCH 179/362] Readme: add info on add-on store --- readme.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index 9f46f7d..18fef85 100644 --- a/readme.md +++ b/readme.md @@ -3,8 +3,9 @@ This package contains a basic template structure for NVDA add-on development, building, distribution and localization. For details about NVDA add-on development, please see the [NVDA Add-on Development Guide](https://github.com/nvdaaddons/DevGuide/wiki/NVDA-Add-on-Development-Guide). The NVDA add-on development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) +Information specific to NV Access add-on store [can be found here](https://github.com/nvaccess/addon-datastore). -Copyright (C) 2012-2022 NVDA Add-on team contributors. +Copyright (C) 2012-2023 NVDA Add-on team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. @@ -32,6 +33,7 @@ This template provides the following features you can use during NVDA add-on dev * To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. * Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. +* Automatic generation of entries for NV Access add-on store (json format). In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): @@ -57,7 +59,7 @@ You need the following software to use this code for your NVDA add-on developmen 1. Create an empty folder to hold the files for your add-on. 2. Copy the **site_scons** folder, and the following files, into your new empty folder: **buildVars.py**, **manifest.ini.tpl**, **manifest-translated.ini.tpl**, **sconstruct**, **.gitignore**, and **.gitattributes** 3. Create an **addon** folder inside your new folder. Inside the **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. -4. In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author and url). +4. In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). 5. Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. 6. Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. @@ -65,10 +67,10 @@ You need the following software to use this code for your NVDA add-on developmen An add-on manifest generated manually or via **buildVars.py** must include the following information: -* Name (string): a unique identifier for the add-on. It must use camel case (e.g. someModule). +* Name (string): a unique identifier for the add-on. It must use camel case (e.g. someModule). This is also used as part of add-on store to identify the add-on uniquely. * Summary (string): name as shown on NVDA's Add-ons Manager. * Description (string): a short detailed description about the add-on. -* Version (string) +* Version (string), ideally number.number with an optional third number, denoting major.minor.patch. * Author (string and an email address): one or more add-on author contact information in the form "name ". * URL (string): a web address where the add-on information can be found (typically community add-ons website address (https://addons.nvda-project.org) is used). * docFileName (string): name of the documentation file. @@ -76,7 +78,7 @@ An add-on manifest generated manually or via **buildVars.py** must include the f * lastTestedNVDAVersion (year.major or year.major.minor): the latest or last tested version of NVDA the add-on is said to be compatible with (e.g. 2020.3). Add-on authors are expected to declare this value after testing add-ons with the version of NVDA specified. * addon_updateChannel (string or None): the update channel for the add-on release. -In addition, the following information must be filled out (not used in the manifest): +In addition, the following information must be filled out (not used in the manifest but used elsewhere such as add-on store): * sourceURL (string): repository URL for the add-on source code. * license (string): the license of the add-on and its source code. From 68b09c14d1c0212534d1e43f51535823a1ee3dd6 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 2 Mar 2023 15:23:49 -0800 Subject: [PATCH 180/362] Add-on store entry generator: remove ad-on name from json file to comply with file naming conventions --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index d22756e..8aa914b 100644 --- a/sconstruct +++ b/sconstruct @@ -191,9 +191,9 @@ def createAddonStoreJson(bundle): versionNumberParsed = [] if len(versionNumberParsed): major, minor, patch = [int(part) for part in versionNumberParsed] - jsonFilename = f'{buildVars.addon_info["addon_name"]}-{major}.{minor}.{patch}.json' + jsonFilename = f'{major}.{minor}.{patch}.json' else: - jsonFilename = f'{buildVars.addon_info["addon_name"]}-{buildVars.addon_info["addon_version"]}.json' + jsonFilename = f'{buildVars.addon_info["addon_version"]}.json' major, minor, patch = 0, 0, 0 print('Generating % s' % jsonFilename) sha256 = hashlib.sha256() From ceb4b2f4e19bb3a807d76101505ce453bd1f0ae9 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 2 Mar 2023 15:28:41 -0800 Subject: [PATCH 181/362] Add-on store: add template json file --- _template_addon_release.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 _template_addon_release.json diff --git a/_template_addon_release.json b/_template_addon_release.json new file mode 100644 index 0000000..c6d3a5f --- /dev/null +++ b/_template_addon_release.json @@ -0,0 +1,29 @@ +{ + "addonId": "easyAddonTech.XYZ", + "addonVersionNumber": { + "major": 21, + "minor": 6, + "patch": 0 + }, + "addonVersionName": "21.06", + "displayName": "My addon", + "publisher": "easyAddonTech", + "description": "Makes doing XYZ easier", + "homepage": "https://github.com/nvaccess/addon-datastore", + "minNVDAVersion": { + "major": 2019, + "minor": 3, + "patch": 0 + }, + "lastTestedVersion": { + "major": 2020, + "minor": 4, + "patch": 0 + }, + "channel": "beta", + "URL": "https://github.com/nvaccess/addon-datastore/releases/download/v0.1.0/myAddon.nvda-addon", + "sha256": "69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82", + "sourceURL": "https://github.com/nvaccess/addon-datastore/", + "license": "GPL v2", + "licenseURL": "https://github.com/nvaccess/addon-datastore/license.MD" +} From 42297732362f0affd45d2791023e0f6ef1f2b370 Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Wed, 8 Mar 2023 15:57:08 +0100 Subject: [PATCH 182/362] Ignore JSON file generated for the add-on store. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a304182..009dcb9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ addon/doc/en/ *.py[co] *.nvda-addon .sconsign.dblite +/[0-9]*.[0-9]*.[0-9]*.json From a4709815ffc4bade316e7701bfa70fb81ca77bcb Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Wed, 8 Mar 2023 18:05:22 +0100 Subject: [PATCH 183/362] Also ignore manifest.ini instead of all .ini files --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 009dcb9..0be8af1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ addon/doc/*.css addon/doc/en/ *_docHandler.py *.html -*.ini +manifest.ini *.mo *.pot *.py[co] From 0dccfa51d2c02d5b26bf732ebc7a12518be8a7cd Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 11 Feb 2023 03:10:41 -0500 Subject: [PATCH 184/362] readme: Corrected the path in the GH workflows comments to ".github/workflows" from ".github/workflow". Added code tags around path. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 18fef85..096320d 100644 --- a/readme.md +++ b/readme.md @@ -25,7 +25,7 @@ This template provides the following features you can use during NVDA add-on dev * Automatic add-on package creation, with naming and version loaded from a centralized build variables file (buildVars.py) or command-line interface. * See packaging section for details on using command-line switches when packaging add-ons with custom version information. * This process will happen automatically when receiving a pull request, and there is also the possibility of manual launch. - * To let the workflow run automatically when pushing to main or master (development) branch, remove the comment for branches line in GitHub Actions (.github/workflow/build_addon.yml). + * To let the workflow run automatically when pushing to main or master (development) branch, remove the comment for branches line in GitHub Actions (`.github/workflows/build_addon.yml`). * If you have created a tag (E.G.: `git tag v1.0 && git push --tag`), then a release will be automatically created and the add-on file will be uploaded as an asset. * Otherwise, with normal commits or with manual startup, you can download the artifacts from the Actions page of your repository. * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. See below for add-on manifest specification. From 192031b354f5fba084c613bb39f37b9f379d74fd Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 11 Feb 2023 03:19:23 -0500 Subject: [PATCH 185/362] readme: In section "To create a new NVDA add-on using this template": * Replaced current formatting in step 2, with code markers around file names. This should make copy-paste operations more straight forward, as opposed to the narrative format used previously. * Add a new step 3, instructing what to copy for workflows usage. --- readme.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index 096320d..cdfa864 100644 --- a/readme.md +++ b/readme.md @@ -57,11 +57,27 @@ You need the following software to use this code for your NVDA add-on developmen ### To create a new NVDA add-on using this template: 1. Create an empty folder to hold the files for your add-on. -2. Copy the **site_scons** folder, and the following files, into your new empty folder: **buildVars.py**, **manifest.ini.tpl**, **manifest-translated.ini.tpl**, **sconstruct**, **.gitignore**, and **.gitattributes** -3. Create an **addon** folder inside your new folder. Inside the **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. -4. In the **buildVars.py** file, change variable **addon_info** with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). -5. Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. -6. Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. +2. Copy the folder: +``` +site_scons +``` +and the following files, into your new empty folder: +``` +buildVars.py +manifest.ini.tpl +manifest-translated.ini.tpl +sconstruct +.gitignore +.gitattributes +``` +3. If you intend to use the provided GitHub workflow, also copy the folder: +``` +.github +``` +4. Create an **addon** folder inside your new folder. Inside the **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. +5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). +6. Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. +7. Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. #### Add-on manifest specification From 23858a8b1fa69a28710329273521223c13030b78 Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 11 Feb 2023 03:35:57 -0500 Subject: [PATCH 186/362] readme: In section "To create a new NVDA add-on using this template:", switched to code markers around filenames in more places, and merged steps 4 and 6 since they were redundant. --- readme.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index cdfa864..a6c4ac5 100644 --- a/readme.md +++ b/readme.md @@ -74,10 +74,9 @@ sconstruct ``` .github ``` -4. Create an **addon** folder inside your new folder. Inside the **addon* folder, create needed folders for the add-on modules (e.g. appModules, synthDrivers, etc.). An add-on may have one or more module folders. +4. Create an `addon` folder inside your new folder. You will put your code in the usual folders for NVDA extensions, under the `addon` folder. For instance: `globalPlugins`, `synthDrivers`, etc. 5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). -6. Put your code in the usual folders for NVDA extension, under the **addon** folder. For instance: globalPlugins, synthDrivers, etc. -7. Gettext translations must be placed into addon\locale\/LC_MESSAGES\nvda.po. +6. Gettext translations must be placed into `addon\locale\/LC_MESSAGES\nvda.po`. #### Add-on manifest specification From b0965d10895cf4516ee2ac4ba781e8d9be60e3a6 Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 11 Feb 2023 03:58:25 -0500 Subject: [PATCH 187/362] readme: Minor typos/grammar --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index a6c4ac5..58045e0 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ This template provides the following features you can use during NVDA add-on dev * Otherwise, with normal commits or with manual startup, you can download the artifacts from the Actions page of your repository. * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. See below for add-on manifest specification. * Compilation of gettext mo files before distribution, when needed. - * To generate a gettext pot file, please run scons pot. A **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the buildVars.i18nSources variable to comply with your requirements. + * To generate a gettext pot file, please run scons pot. An **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the `buildVars.i18nSources` variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. * Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. * Automatic generation of entries for NV Access add-on store (json format). @@ -38,7 +38,7 @@ This template provides the following features you can use during NVDA add-on dev In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): * Flake8 (flake8.ini): a base configuration file for Flake8 linting tool based on NVDA's own Flake8 configuration file. -* Configuration for VS Code. It requires NVDA`s repo at the same level that add-on repos, with prepared source code (`scons source`). +* Configuration for VS Code. It requires NVDA's repo at the same level as the add-on repo, with prepared source code (`scons source`). * Press `control+shift+m`after saving a file to search for problems. * Use arrow and tab keys for the autocompletion feature. * Press `control+shift+p`to open the commands palette and search for recommended extensions to install or check if they are installed. From 069a3844200e9580649ac5c18ee45059e09e6590 Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 11 Feb 2023 04:02:38 -0500 Subject: [PATCH 188/362] readme: Added a note to requirements section, about using cloud based build/packaging environments. --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 58045e0..c3e8dfe 100644 --- a/readme.md +++ b/readme.md @@ -52,6 +52,8 @@ You need the following software to use this code for your NVDA add-on developmen * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). * Markdown 3.3.0 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. +Note, that you may not need these tools in a local build environment, if you are using [Appveyor](https://appveyor.com/) or [GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions), to build and package your add-ons. + ## Usage ### To create a new NVDA add-on using this template: From f83c84ec763886c31708b15b42c8fc1ae6fae93a Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 11 Feb 2023 04:06:54 -0500 Subject: [PATCH 189/362] readme: Replaced more bolding markdown with code markers, and added other missing code markers. --- readme.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index c3e8dfe..cd1a226 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ This template provides the following features you can use during NVDA add-on dev * Otherwise, with normal commits or with manual startup, you can download the artifacts from the Actions page of your repository. * Manifest file creation using a template (manifest.ini.tpl). Build variables are replaced on this template. See below for add-on manifest specification. * Compilation of gettext mo files before distribution, when needed. - * To generate a gettext pot file, please run scons pot. An **addon-name.pot** file will be created with all gettext messages for your add-on. You need to check the `buildVars.i18nSources` variable to comply with your requirements. + * To generate a gettext pot file, please run `scons pot`. An `addon-name.pot` file will be created with all gettext messages for your add-on. You need to check the `buildVars.i18nSources` variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. * Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. * Automatic generation of entries for NV Access add-on store (json format). @@ -82,7 +82,7 @@ sconstruct #### Add-on manifest specification -An add-on manifest generated manually or via **buildVars.py** must include the following information: +An add-on manifest generated manually or via `buildVars.py` must include the following information: * Name (string): a unique identifier for the add-on. It must use camel case (e.g. someModule). This is also used as part of add-on store to identify the add-on uniquely. * Summary (string): name as shown on NVDA's Add-ons Manager. @@ -103,13 +103,13 @@ In addition, the following information must be filled out (not used in the manif ### To manage documentation files for your addon: -1. Copy the **readme.md** file for your add-on to the first created folder, where you copied **buildVars.py**. You can also copy **style.css** to improve the presentation of HTML documents. -2. Documentation files (named **readme.md**) must be placed into addon\doc\/. +1. Copy the `readme.md` file for your add-on to the first created folder, where you copied `buildVars.py`. You can also copy `style.css` to improve the presentation of HTML documents. +2. Documentation files (named `readme.md`) must be placed into `addon\doc\/`. ### To package the add-on for distribution: -1. Open a command line, change to the folder that has the **sconstruct** file (usually the root of your add-on development folder) and run the **scons** command. The created add-on, if there were no errors, is placed in the current directory. -2. You can further customize variables in the **buildVars.py** file. +1. Open a command line, change to the folder that has the `sconstruct` file (usually the root of your add-on development folder) and run the `scons` command. The created add-on, if there were no errors, is placed in the current directory. +2. You can further customize variables in the `buildVars.py` file. 3. You can also customize version and update channel information from command line by passing the following switches when running scons: * version: add-on version string. * versionNumber: add-on version number of the form major.minor.patch (all integers) From 02ac23a8864bdfd2cee685b20ede62dadcbaeb64 Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 11 Feb 2023 06:32:31 -0500 Subject: [PATCH 190/362] readme: Added the need to copy .pre-commit-config.yaml to the list of files/folders to copy. --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index cd1a226..b52bb8e 100644 --- a/readme.md +++ b/readme.md @@ -76,6 +76,10 @@ sconstruct ``` .github ``` +and file: +``` +.pre-commit-config.yaml +``` 4. Create an `addon` folder inside your new folder. You will put your code in the usual folders for NVDA extensions, under the `addon` folder. For instance: `globalPlugins`, `synthDrivers`, etc. 5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). 6. Gettext translations must be placed into `addon\locale\/LC_MESSAGES\nvda.po`. From ca9a518bd30340785f65f0955740eefcbeb95cac Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Mon, 13 Mar 2023 03:03:58 -0400 Subject: [PATCH 191/362] Added a note to step 5 in readme, about adjusting paths in buildVars. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b52bb8e..c50e6f3 100644 --- a/readme.md +++ b/readme.md @@ -81,7 +81,7 @@ and file: .pre-commit-config.yaml ``` 4. Create an `addon` folder inside your new folder. You will put your code in the usual folders for NVDA extensions, under the `addon` folder. For instance: `globalPlugins`, `synthDrivers`, etc. -5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). +5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). Also, be sure to carefully set the paths contained in the other variables in that file. 6. Gettext translations must be placed into `addon\locale\/LC_MESSAGES\nvda.po`. #### Add-on manifest specification From 05169a55cf6fbc9eb7da0907df916e567ed1ceec Mon Sep 17 00:00:00 2001 From: Florian Beijers Date: Mon, 20 Mar 2023 19:27:30 +0100 Subject: [PATCH 192/362] Clear up the VS Code procedure --- readme.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index c50e6f3..a6bdbd2 100644 --- a/readme.md +++ b/readme.md @@ -38,16 +38,18 @@ This template provides the following features you can use during NVDA add-on dev In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): * Flake8 (flake8.ini): a base configuration file for Flake8 linting tool based on NVDA's own Flake8 configuration file. -* Configuration for VS Code. It requires NVDA's repo at the same level as the add-on repo, with prepared source code (`scons source`). - * Press `control+shift+m`after saving a file to search for problems. +* Configuration for VS Code. It requires NVDA's repo at the same level as the add-on folder containing your actual source files, with prepared source code (`scons source`). preparing the source code is a step in the instructions for building NVDA itself, see [The NVDA Repository](https://github.com/nvaccess/nvda) for details. + * Place the .vscode in this repo within the addon folder, where your add-on source files (will) reside. The settings file within this folder assumes the NVDA repository is within the parent folder of this folder. If your addon folder is within the addonTemplate folder, then your NVDA repository folder needs to also be within the addonTemplate folder, or the source will not be found. + * Open the addon folder in VS Code. This should initialize VS Code with the correct settings and provide you with code completion and other VS Code features. + * Press `control+shift+m` after saving a file to search for problems. * Use arrow and tab keys for the autocompletion feature. - * Press `control+shift+p`to open the commands palette and search for recommended extensions to install or check if they are installed. + * Press `control+shift+p` to open the commands palette and search for recommended extensions to install or check if they are installed. ## Requirements You need the following software to use this code for your NVDA add-on development and packaging: -* a Python distribution (3.7 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. +* a Python distribution (3.7 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.7. * Scons - [Website](https://www.scons.org/) - version 4.3.0 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). * Markdown 3.3.0 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. From 9fb0b93fdd3f0e2d9e3fb0ba2e5c87b717da4605 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 26 Mar 2023 08:05:05 -0700 Subject: [PATCH 193/362] SConstruct: default daily build (dev channel) name changed from yyyymmdd-dev to yyyymmdd.0.0 to comply with NV Access add-on store requirements. Instead of a pure string for version name, use major.minor.patch. In case of daily builds from dev channel, use date/major.minor.patch. With this convention, the first daily build will be yyyymmdd.0.0. This does not affect beta channel, and even for dev channel releases, add-on authors can specify their own number.number.number release if submitting to add-on store from SCons command line interface. --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 8aa914b..01f05a6 100644 --- a/sconstruct +++ b/sconstruct @@ -101,7 +101,7 @@ if env["dev"]: buildDate = datetime.datetime.now() year, month, day = str(buildDate.year), str(buildDate.month), str(buildDate.day) versionTimestamp = "".join([year, month.zfill(2), day.zfill(2)]) - env["addon_version"] = f"{versionTimestamp}-dev" + env["addon_version"] = f"{versionTimestamp}.0.0" env["versionNumber"] = f"{versionTimestamp}.0.0" env["channel"] = "dev" elif env["version"] is not None: From 5b82e329d0bf2d1dbf21ef0f23505df23d4275b6 Mon Sep 17 00:00:00 2001 From: abdel792 Date: Fri, 5 May 2023 19:10:46 +0200 Subject: [PATCH 194/362] Corrected the translation of the documentation title in the SConstruct file. Changed line 302 from: env.Depends(htmlFile, mdFile) To: env.Depends(htmlFile, [mdFile, moFile]) The generation of html files must also depend on mo files. Uncompiled po files provide no translations. Without this correction, the titles of the documentations are never translated. --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 01f05a6..3af078a 100644 --- a/sconstruct +++ b/sconstruct @@ -299,7 +299,7 @@ for file in pythonFiles: createAddonHelp("addon") for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): htmlFile = env.markdown(mdFile) - env.Depends(htmlFile, mdFile) + env.Depends(htmlFile, [mdFile, moFile]) env.Depends(addon, htmlFile) # Pot target From 6663b5c5e9775f01e2c1d04f687b06a48390377e Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Sat, 10 Jun 2023 05:42:49 -0400 Subject: [PATCH 195/362] Fix-up of #28 to handle the situation when there are no existing translations. Pr #28 included moFile in the dependency for HTML file generation. However if there was no moFile set, likely because there has not been any translation yet, sconstruct failed on a NameError. To solve this, I put the access of moFile in a try-except-else block. --- sconstruct | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 3af078a..f1bad99 100644 --- a/sconstruct +++ b/sconstruct @@ -299,7 +299,12 @@ for file in pythonFiles: createAddonHelp("addon") for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): htmlFile = env.markdown(mdFile) - env.Depends(htmlFile, [mdFile, moFile]) + try: # It is possible that no moFile was set, because an add-on has no translations. + moFile + except NameError: # Runs if there is no moFile + env.Depends(htmlFile, mdFile) + else: # Runs if there is a moFile + env.Depends(htmlFile, [mdFile, moFile]) env.Depends(addon, htmlFile) # Pot target From b6faf9144777aeeff6171e24dd243152700bc1a4 Mon Sep 17 00:00:00 2001 From: derek riemer Date: Sat, 17 Jun 2023 15:15:30 -0600 Subject: [PATCH 196/362] Depend on the correct moFile for a given md file. We need the correct title for a given languages translated documentation, which comes from the moFile. However, the previous version of the build script accidentally depended on a variable assigned inside the for loop which was used to assign the languages actual moFile. This loop variable is assigned inside the loop, and not outside it, is overridden on each iteration, and is not persisted anywhere so we cann reference the correct moFile when we later generate the html. This pr fixes that. in this pr, I create a moByLang dictionary, and store the moFile as a value. The key for this moFile is the language code. That way, the html for language KR depends on the moFile for kr, and not the moFile for whatever language was last assigned in the for loop. That way, if the ES languagges po file updates, the dependency system will correctly attribute that Korean is the language we need to regenenrate HTML for. This also undoes the try/except logic that incorrectly hid the real issue, which was the inappropriate refrencing of a for loop variable that may have never been created. --- sconstruct | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sconstruct b/sconstruct index f1bad99..9596a33 100644 --- a/sconstruct +++ b/sconstruct @@ -279,9 +279,11 @@ addon = env.NVDAAddon(addonFile, env.Dir('addon')) langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated +moByLang = {} for dir in langDirs: poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) moFile = env.gettextMoFile(poFile) + moByLang[dir] = moFile env.Depends(moFile, poFile) translatedManifest = env.NVDATranslatedManifest( dir.File("manifest.ini"), @@ -298,13 +300,14 @@ for file in pythonFiles: # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager createAddonHelp("addon") for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): + # the title of the html file is translated based on the contents of something in the moFile for a language. + # Thus, we find the moFile for this language and depend on it if it exists. + lang = os.path.basename(os.path.dirname(mdFile.get_abspath())) + moFile = moByLang.get(lang) htmlFile = env.markdown(mdFile) - try: # It is possible that no moFile was set, because an add-on has no translations. - moFile - except NameError: # Runs if there is no moFile - env.Depends(htmlFile, mdFile) - else: # Runs if there is a moFile - env.Depends(htmlFile, [mdFile, moFile]) + env.Depends(htmlFile, mdFile) + if moFile: + env.Depends(htmlFile, moFile) env.Depends(addon, htmlFile) # Pot target From 08e3a08b1b004ca09b2434bd883b1fcfb7f2f9aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Golonka?= Date: Thu, 7 Sep 2023 13:59:11 +0200 Subject: [PATCH 197/362] VS Code config: Add functions used for translation to the list of recognized build-in names. --- .vscode/settings.json | 4 +--- .vscode/typings/__builtins__.pyi | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 .vscode/typings/__builtins__.pyi diff --git a/.vscode/settings.json b/.vscode/settings.json index 7c58677..f99518a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,9 +14,7 @@ "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "editor.insertSpaces": false, - "python.analysis.diagnosticSeverityOverrides": { - "reportUndefinedVariable": "none" - }, + "python.analysis.stubPath": "${workspaceFolder}/.vscode/typings", "python.analysis.extraPaths": [ "../nvda/source", "../nvda/miscDeps/python" diff --git a/.vscode/typings/__builtins__.pyi b/.vscode/typings/__builtins__.pyi new file mode 100644 index 0000000..88febec --- /dev/null +++ b/.vscode/typings/__builtins__.pyi @@ -0,0 +1,6 @@ +def _(msg: str) -> str: + ... + + +def pgettext(context: str, message: str) -> str: + ... From 9e26d87590fd9044621bfe23220c793f1e7916ad Mon Sep 17 00:00:00 2001 From: hwf1324 <1398969445@qq.com> Date: Fri, 22 Sep 2023 17:44:32 +0800 Subject: [PATCH 198/362] Fixed the error that the NVDA Python virtual environment could not be found by default. --- .vscode/settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f99518a..8741d16 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,7 @@ "python.autoComplete.extraPaths": [ "../nvda/source", "../nvda/miscDeps/python" - ], + ], "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "editor.insertSpaces": false, @@ -19,5 +19,5 @@ "../nvda/source", "../nvda/miscDeps/python" ], - "python.defaultInterpreterPath": "../nvda/.venv/scripts/python.exe" + "python.defaultInterpreterPath": "${workspaceFolder}/../nvda/.venv/scripts/python.exe" } From 84ec6039fc92d03198c71ac0c0dae7d4a5df61e0 Mon Sep 17 00:00:00 2001 From: hwf1324 <1398969445@qq.com> Date: Fri, 22 Sep 2023 17:57:09 +0800 Subject: [PATCH 199/362] Migration to Python Flake8 Extensions --- .vscode/extensions.json | 3 ++- .vscode/settings.json | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 75fa7aa..4408de6 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -5,7 +5,8 @@ "recommendations": [ "ms-python.python", "ms-python.vscode-pylance", - "redhat.vscode-yaml" + "redhat.vscode-yaml", + "ms-python.flake8" // flake8 extension version <= v2023.4.0 ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [] diff --git a/.vscode/settings.json b/.vscode/settings.json index 8741d16..6126d28 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,12 +1,9 @@ { "editor.accessibilitySupport": "on", - "python.linting.enabled": true, - "python.linting.maxNumberOfProblems": 10000, - "python.linting.flake8Args": [ + "flake8.args": [ "--config=flake8.ini" ], - "python.linting.flake8Enabled": true, - "python.linting.pylintEnabled": false, + "flake8.importStrategy": "fromEnvironment", "python.autoComplete.extraPaths": [ "../nvda/source", "../nvda/miscDeps/python" From 46383edc181bf5a0a607f7fb3cf6f93753e7741b Mon Sep 17 00:00:00 2001 From: hwf1324 <1398969445@qq.com> Date: Mon, 16 Oct 2023 14:00:59 +0800 Subject: [PATCH 200/362] Upgrade python 3.11 --- .vscode/extensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 4408de6..514e061 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -6,7 +6,7 @@ "ms-python.python", "ms-python.vscode-pylance", "redhat.vscode-yaml", - "ms-python.flake8" // flake8 extension version <= v2023.4.0 + "ms-python.flake8" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [] From bda5b59577d37a5c279985c3b22885d34900c3e5 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 21 Oct 2023 05:34:31 -0600 Subject: [PATCH 201/362] SConstruct: remove json creation tool. Closes #36. In the past, add-on store required submitting json files. Now the store uses a dedicated submission form where submitters can enter download URL and json will be generated afterwards. --- sconstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index f1bad99..dde28af 100644 --- a/sconstruct +++ b/sconstruct @@ -170,7 +170,8 @@ def createAddonBundleFromPath(path, dest): absPath = os.path.join(dir, filename) if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle) - createAddonStoreJson(dest) + # Add-on store does not require submitting json files. + # createAddonStoreJson(dest) return dest From e3fa6d55c9374e7e6dc130af8735bd8deff232ae Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 21 Oct 2023 05:45:11 -0600 Subject: [PATCH 202/362] Flake8: add ngettext and npgettext variants. NVDA 2023.2 and later: allow add-ons to work with pural forms, either without context (ngettext) or with context (npgettext). --- flake8.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake8.ini b/flake8.ini index 8253925..cb731d8 100644 --- a/flake8.ini +++ b/flake8.ini @@ -36,7 +36,9 @@ ignore = builtins = # inform flake8 about functions we consider built-in. _, # translation lookup + ngettext, # translation lookup pgettext, # translation lookup + npgettext, # translation lookup exclude = # don't bother looking in the following subdirectories / files. .git, From f0fff5d66e1f13acc013af76701dfdb378fbc47b Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 7 May 2024 09:00:44 -0600 Subject: [PATCH 203/362] SConstruct: update copyright year --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index dde28af..f5312d9 100644 --- a/sconstruct +++ b/sconstruct @@ -1,5 +1,5 @@ # NVDA add-on template SCONSTRUCT file -# Copyright (C) 2012-2023 Rui Batista, Noelia Martinez, Joseph Lee +# Copyright (C) 2012-2024 Rui Batista, Noelia Martinez, Joseph Lee # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. From 2354f5e6e6bfb4824d06af94a01ebc91ba0f4190 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 7 May 2024 09:01:13 -0600 Subject: [PATCH 204/362] SConstruct: remove add-on store json generator as the store wil generate it when add-ons are submitted --- sconstruct | 79 +----------------------------------------------------- 1 file changed, 1 insertion(+), 78 deletions(-) diff --git a/sconstruct b/sconstruct index f5312d9..879fe10 100644 --- a/sconstruct +++ b/sconstruct @@ -77,7 +77,7 @@ def mdTool(env): def validateVersionNumber(key, val, env): # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. - # Ignore all this if version number is not specified, in which case json generator will validate this info. + # Ignore all this if version number is not specified. if val == "0.0.0": return versionNumber = val.split(".") @@ -170,86 +170,9 @@ def createAddonBundleFromPath(path, dest): absPath = os.path.join(dir, filename) if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle) - # Add-on store does not require submitting json files. - # createAddonStoreJson(dest) return dest -def createAddonStoreJson(bundle): - """Creates add-on store JSON file from an add-on package and manifest data.""" - import json - import hashlib - # Set different json file names and version number properties based on version number parsing results. - if env["versionNumber"] == "0.0.0": - env["versionNumber"] = buildVars.addon_info["addon_version"] - versionNumberParsed = env["versionNumber"].split(".") - if all([part.isnumeric() for part in versionNumberParsed]): - if len(versionNumberParsed) == 1: - versionNumberParsed += ["0", "0"] - elif len(versionNumberParsed) == 2: - versionNumberParsed.append("0") - else: - versionNumberParsed = [] - if len(versionNumberParsed): - major, minor, patch = [int(part) for part in versionNumberParsed] - jsonFilename = f'{major}.{minor}.{patch}.json' - else: - jsonFilename = f'{buildVars.addon_info["addon_version"]}.json' - major, minor, patch = 0, 0, 0 - print('Generating % s' % jsonFilename) - sha256 = hashlib.sha256() - with open(bundle, "rb") as f: - for byte_block in iter(lambda: f.read(65536), b""): - sha256.update(byte_block) - hashValue = sha256.hexdigest() - try: - minimumNVDAVersion = buildVars.addon_info["addon_minimumNVDAVersion"].split(".") - except AttributeError: - minimumNVDAVersion = [0, 0, 0] - minMajor, minMinor = minimumNVDAVersion[:2] - minPatch = minimumNVDAVersion[-1] if len(minimumNVDAVersion) == 3 else "0" - try: - lastTestedNVDAVersion = buildVars.addon_info["addon_lastTestedNVDAVersion"].split(".") - except AttributeError: - lastTestedNVDAVersion = [0, 0, 0] - lastTestedMajor, lastTestedMinor = lastTestedNVDAVersion[:2] - lastTestedPatch = lastTestedNVDAVersion[-1] if len(lastTestedNVDAVersion) == 3 else "0" - channel = buildVars.addon_info["addon_updateChannel"] - if channel is None: - channel = "stable" - addonStoreEntry = { - "addonId": buildVars.addon_info["addon_name"], - "displayName": buildVars.addon_info["addon_summary"], - "URL": "", - "description": buildVars.addon_info["addon_description"], - "sha256": hashValue, - "homepage": buildVars.addon_info["addon_url"], - "addonVersionName": buildVars.addon_info["addon_version"], - "addonVersionNumber": { - "major": major, - "minor": minor, - "patch": patch - }, - "minNVDAVersion": { - "major": int(minMajor), - "minor": int(minMinor), - "patch": int(minPatch) - }, - "lastTestedVersion": { - "major": int(lastTestedMajor), - "minor": int(lastTestedMinor), - "patch": int(lastTestedPatch) - }, - "channel": channel, - "publisher": "", - "sourceURL": buildVars.addon_info["addon_sourceURL"], - "license": buildVars.addon_info["addon_license"], - "licenseURL": buildVars.addon_info["addon_licenseURL"], - } - with open(jsonFilename, "w") as addonStoreJson: - json.dump(addonStoreEntry, addonStoreJson, indent="\t") - - def generateManifest(source, dest): addon_info = buildVars.addon_info with codecs.open(source, "r", "utf-8") as f: From 37f2b5907b0a04b9b757d5074289997ef984f6f9 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 7 May 2024 09:01:37 -0600 Subject: [PATCH 205/362] SConstruct: ensure Python 3.10 or later --- sconstruct | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 879fe10..353bd0e 100644 --- a/sconstruct +++ b/sconstruct @@ -14,8 +14,11 @@ import sys # Linters aren't aware about them. # To avoid Flake8 F821 warnings about them they are imported explicitly. # When using other Scons functions please add them to the line below. -from SCons.Script import BoolVariable, Builder, Copy, Environment, Variables +from SCons.Script import BoolVariable, Builder, Copy, Environment, Variables, EnsurePythonVersion # NOQA: E501, F401 +# Add-on localization exchange facility and the template requires Python 3.10. +# For best practice, use Python 3.11 or later to align with NVDA development. +EnsurePythonVersion(3, 10) sys.dont_write_bytecode = True # Bytecode should not be written for build vars module to keep the repository root folder clean. From 9f7fe8465b98c59cb52257df52dcf1df7588859b Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 7 May 2024 09:06:47 -0600 Subject: [PATCH 206/362] Readme: update copyrights and Python 3.11 requirement --- readme.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index a6bdbd2..b9ed90b 100644 --- a/readme.md +++ b/readme.md @@ -5,19 +5,16 @@ For details about NVDA add-on development, please see the [NVDA Add-on Developme The NVDA add-on development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) Information specific to NV Access add-on store [can be found here](https://github.com/nvaccess/addon-datastore). -Copyright (C) 2012-2023 NVDA Add-on team contributors. +Copyright (C) 2012-2024 NVDA Add-on team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. - - [alekssamos](https://github.com/alekssamos/) added automatic package of add-ons through Github Actions. For details about Github Actions please see the [Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). Copyright (C) 2022 alekssamos - ## Features This template provides the following features you can use during NVDA add-on development and packaging: @@ -49,8 +46,8 @@ In addition, this template includes configuration files for the following tools You need the following software to use this code for your NVDA add-on development and packaging: -* a Python distribution (3.7 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.7. -* Scons - [Website](https://www.scons.org/) - version 4.3.0 or later. You can install it via PIP. +* a Python distribution (3.11 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.11. +* Scons - [Website](https://www.scons.org/) - version 4.5.2 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). * Markdown 3.3.0 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. From ac57655a4ae6298a7c21989383328b5aec7da68a Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 7 May 2024 09:09:57 -0600 Subject: [PATCH 207/362] Readme: add-ons manager -> add-on store, update URL manifest key description to point to add-on repo --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index b9ed90b..2209194 100644 --- a/readme.md +++ b/readme.md @@ -88,11 +88,11 @@ and file: An add-on manifest generated manually or via `buildVars.py` must include the following information: * Name (string): a unique identifier for the add-on. It must use camel case (e.g. someModule). This is also used as part of add-on store to identify the add-on uniquely. -* Summary (string): name as shown on NVDA's Add-ons Manager. +* Summary (string): name as shown on NVDA's Add-on store. * Description (string): a short detailed description about the add-on. * Version (string), ideally number.number with an optional third number, denoting major.minor.patch. * Author (string and an email address): one or more add-on author contact information in the form "name ". -* URL (string): a web address where the add-on information can be found (typically community add-ons website address (https://addons.nvda-project.org) is used). +* URL (string): a web address where the add-on information can be found such as add-on repository. * docFileName (string): name of the documentation file. * minimumNVDAVersion (year.major or year.major.minor): the earliest version of NVDA the add-on is compatible with (e.g. 2019.3). Add-ons are expected to use features introduced in this version of NVDA or declare compatibility with it. * lastTestedNVDAVersion (year.major or year.major.minor): the latest or last tested version of NVDA the add-on is said to be compatible with (e.g. 2020.3). Add-on authors are expected to declare this value after testing add-ons with the version of NVDA specified. From b8bf4722e56f84245775f7aa4f695afcdd2846cc Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 8 May 2024 10:55:09 -0600 Subject: [PATCH 208/362] SConstruct: replace string interpolation (%s) with formatted string literals (f strings) --- sconstruct | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sconstruct b/sconstruct index 353bd0e..2a4130a 100644 --- a/sconstruct +++ b/sconstruct @@ -51,12 +51,12 @@ def md2html(source, dest): # Optimization: build resulting HTML text in one go instead of writing parts separately. docText = "\n".join([ "", - "" % lang, + f"", "", "" "", "", - "%s" % title, + f"{title}", "\n", htmlText, "\n" @@ -68,7 +68,7 @@ def md2html(source, dest): def mdTool(env): mdAction = env.Action( lambda target, source, env: md2html(source[0].path, target[0].path), - lambda target, source, env: 'Generating % s' % target[0], + lambda target, source, env: f"Generating {target[0]}", ) mdBuilder = env.Builder( action=mdAction, @@ -121,7 +121,7 @@ addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") def addonGenerator(target, source, env, for_signature): action = env.Action( lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, - lambda target, source, env: "Generating Addon %s" % target[0] + lambda target, source, env: f"Generating Addon {target[0]}" ) return action @@ -129,7 +129,7 @@ def addonGenerator(target, source, env, for_signature): def manifestGenerator(target, source, env, for_signature): action = env.Action( lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, - lambda target, source, env: "Generating manifest %s" % target[0] + lambda target, source, env: f"Generating manifest {target[0]}" ) return action @@ -139,7 +139,7 @@ def translatedManifestGenerator(target, source, env, for_signature): lang = os.path.basename(dir) action = env.Action( lambda target, source, env: generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None, - lambda target, source, env: "Generating translated manifest %s" % target[0] + lambda target, source, env: f"Generating translated manifest {target[0]}" ) return action From 933fd68649796c34b4f59a827ad8ba8c7ca5a6f0 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 9 May 2024 08:19:15 -0600 Subject: [PATCH 209/362] buildVars: add braileTables dictionary. Re #38. NVDA 2024.3 introduces custom braille tables support, implemented in add-ons via a new manifest section named 'brailleTables'. In the add-on template, support it via a new 'brailleTables' dictionary that records a custom braille table (key) and associated manifest section entries (displayName (name of the table shown to users), contracted (true/false), input (true/false), output (true/false)). The new dictionary will be picked up by SCons when packaging custom braille translations table add-on, with displayName field to be translated. --- buildVars.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/buildVars.py b/buildVars.py index 73ae47e..a95a1c5 100644 --- a/buildVars.py +++ b/buildVars.py @@ -77,3 +77,13 @@ def _(arg): # Extensions string must be of the form "markdown.extensions.extensionName" # e.g. "markdown.extensions.tables" to add tables. markdownExtensions = [] + +# Custom braille translation tables +# If your add-on includes custom braille tables (most will not), fill out this dictionary. +# Each key is a dictionary named according to braille table file name, +# with keys inside recording the following attributes: +# displayName (name of the table shown to users and translatable), +# contracted (contracted (True) or uncontracted (False) braille code), +# output (shown in output table list), +# input (shown in input table list). +brailleTables = {} From 4b844abab892660d36b7bac6139a4654f441396a Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 9 May 2024 08:21:39 -0600 Subject: [PATCH 210/362] SConstruct: add custom braille tables section to manifest (actual and localized data) if present. Re #38. After processing root manifest section (actual and localized), process custom braille translation tables section if at least one custom braille table and their attriutes are defined (buildVars.brailleTables is not empty). --- sconstruct | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sconstruct b/sconstruct index 2a4130a..dd0557d 100644 --- a/sconstruct +++ b/sconstruct @@ -177,10 +177,20 @@ def createAddonBundleFromPath(path, dest): def generateManifest(source, dest): + # Prepare the root manifest section addon_info = buildVars.addon_info with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() manifest = manifest_template.format(**addon_info) + # Add additional manifest sections such as custom braile tables + # Custom braille translation tables + if buildVars.brailleTables: + manifest_brailleTables = ["\n[brailleTables]"] + for table in buildVars.brailleTables.keys(): + manifest_brailleTables.append(f"[[{table}]]") + for key, val in buildVars.brailleTables[table].items(): + manifest_brailleTables.append(f"{key} = {val}") + manifest += "\n".join(manifest_brailleTables) with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) @@ -193,6 +203,15 @@ def generateTranslatedManifest(source, language, out): with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() result = manifest_template.format(**vars) + # Add additional manifest sections such as custom braile tables + # Custom braille translation tables + if buildVars.brailleTables: + result_brailleTables = ["\n[brailleTables]"] + for table in buildVars.brailleTables.keys(): + result_brailleTables.append(f"[[{table}]]") + # Fetch display name only. + result_brailleTables.append(f"displayName = {buildVars.brailleTables[table]["displayName"]}") + result += "\n".join(result_brailleTables) with codecs.open(out, "w", "utf-8") as f: f.write(result) From bc2f98049b262ead056bd57575282aee7f8ba329 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 9 May 2024 08:25:03 -0600 Subject: [PATCH 211/362] SConstruct: add new lines at the end of custom braille tables section if present --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index dd0557d..b739184 100644 --- a/sconstruct +++ b/sconstruct @@ -190,7 +190,7 @@ def generateManifest(source, dest): manifest_brailleTables.append(f"[[{table}]]") for key, val in buildVars.brailleTables[table].items(): manifest_brailleTables.append(f"{key} = {val}") - manifest += "\n".join(manifest_brailleTables) + manifest += f"{'\n'.join(manifest_brailleTables)}\n" with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) @@ -211,7 +211,7 @@ def generateTranslatedManifest(source, language, out): result_brailleTables.append(f"[[{table}]]") # Fetch display name only. result_brailleTables.append(f"displayName = {buildVars.brailleTables[table]["displayName"]}") - result += "\n".join(result_brailleTables) + result += f"{'\n'.join(result_brailleTables)}\n" with codecs.open(out, "w", "utf-8") as f: f.write(result) From a22aa7ea3e6400b6cd0101fe116971c583bfdad3 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 9 May 2024 08:55:00 -0600 Subject: [PATCH 212/362] Readme: document custom braille translation table manifest specificiation. Re #38 --- readme.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 2209194..332f063 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# NVDA Add-on Scons Template # +# NVDA Add-on Scons Template This package contains a basic template structure for NVDA add-on development, building, distribution and localization. For details about NVDA add-on development, please see the [NVDA Add-on Development Guide](https://github.com/nvdaaddons/DevGuide/wiki/NVDA-Add-on-Development-Guide). @@ -30,7 +30,6 @@ This template provides the following features you can use during NVDA add-on dev * To generate a gettext pot file, please run `scons pot`. An `addon-name.pot` file will be created with all gettext messages for your add-on. You need to check the `buildVars.i18nSources` variable to comply with your requirements. * Automatic generation of manifest localization files directly from gettext po files. Please make sure buildVars.py is included in i18nFiles. * Automatic generation of HTML documents from markdown (.md) files, to manage documentation in different languages. -* Automatic generation of entries for NV Access add-on store (json format). In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): @@ -80,7 +79,7 @@ and file: .pre-commit-config.yaml ``` 4. Create an `addon` folder inside your new folder. You will put your code in the usual folders for NVDA extensions, under the `addon` folder. For instance: `globalPlugins`, `synthDrivers`, etc. -5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). Also, be sure to carefully set the paths contained in the other variables in that file. +5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). Also, be sure to carefully set the paths contained in the other variables in that file. If you need to use custom Markdown extensions, original add-on interface language is not English, or include custom braille translations tables, be sure to fil out markdown list, base language variable, and braille tables dictioanry, respectively. 6. Gettext translations must be placed into `addon\locale\/LC_MESSAGES\nvda.po`. #### Add-on manifest specification @@ -98,12 +97,24 @@ An add-on manifest generated manually or via `buildVars.py` must include the fol * lastTestedNVDAVersion (year.major or year.major.minor): the latest or last tested version of NVDA the add-on is said to be compatible with (e.g. 2020.3). Add-on authors are expected to declare this value after testing add-ons with the version of NVDA specified. * addon_updateChannel (string or None): the update channel for the add-on release. -In addition, the following information must be filled out (not used in the manifest but used elsewhere such as add-on store): +In addition, the following information must be filled out (not used in the manifest but used elsewhere such as add-on store) in buildVars: * sourceURL (string): repository URL for the add-on source code. * license (string): the license of the add-on and its source code. * licenseURL: the URL for the license file. +##### Custom add-on information + +In addition to the core manifest data, custom add-on information can be specified. As of 2024, the template supports generation of custom braille translation tables. Information on custom braille tables must be specified in buildVars under `braileTables` dictionary as follows: + +* Table name (string key for a nested dictionary): each `brailleTables` entry is a filename for the included custom braille table placed in `brailleTables` folder inside `addon` folder. This nested dictionary should specify: + * displayName (string): the name of the table shown to users and is translatable. + * contracted (True/False): is this a contracted braille table (True) or uncontracted (False). + * output (True/False): the table can be listed in output table list in NVDA's braille settings. + * input (True/False): braille can be entered using this table and listed in input table list in NVDA's braille settings. + +Note: you must fill out this dictionary if at least one custom braille table is included in the add-on. If not, leave the dictionary empty. + ### To manage documentation files for your addon: 1. Copy the `readme.md` file for your add-on to the first created folder, where you copied `buildVars.py`. You can also copy `style.css` to improve the presentation of HTML documents. From d41f11c3ab133140f8ac9b59a0078a1bc9ee1a88 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 9 May 2024 09:22:16 -0600 Subject: [PATCH 213/362] SConstruct: use getattr to make sure buildVars.brailleTables is defined. Re #38. It might be possible that buildVars.brailleTables dictionary might be missing becasue the updated SConstruct and buildVars are not copied to add-on repositories. Therefore, check the attriute and work with an empty dictionary if buildVars.brailleTables is missing. --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index b739184..f31fb47 100644 --- a/sconstruct +++ b/sconstruct @@ -184,7 +184,7 @@ def generateManifest(source, dest): manifest = manifest_template.format(**addon_info) # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if buildVars.brailleTables: + if getattr(buildVars, "brailleTables", {}): manifest_brailleTables = ["\n[brailleTables]"] for table in buildVars.brailleTables.keys(): manifest_brailleTables.append(f"[[{table}]]") @@ -205,7 +205,7 @@ def generateTranslatedManifest(source, language, out): result = manifest_template.format(**vars) # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if buildVars.brailleTables: + if getattr(buildVars, "brailleTables", {}): result_brailleTables = ["\n[brailleTables]"] for table in buildVars.brailleTables.keys(): result_brailleTables.append(f"[[{table}]]") From b82cbfcf49def764605e0acd662020e5816c3e43 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 11 May 2024 08:05:44 -0600 Subject: [PATCH 214/362] SConstruct: do not use F strings when generating braille tables manifest text due to syntax error in baskslash character use in expressions (resolved in Python 3.12) --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index f31fb47..36804f1 100644 --- a/sconstruct +++ b/sconstruct @@ -190,7 +190,7 @@ def generateManifest(source, dest): manifest_brailleTables.append(f"[[{table}]]") for key, val in buildVars.brailleTables[table].items(): manifest_brailleTables.append(f"{key} = {val}") - manifest += f"{'\n'.join(manifest_brailleTables)}\n" + manifest += "\n".join(manifest_brailleTables) + "\n" with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) @@ -211,7 +211,7 @@ def generateTranslatedManifest(source, language, out): result_brailleTables.append(f"[[{table}]]") # Fetch display name only. result_brailleTables.append(f"displayName = {buildVars.brailleTables[table]["displayName"]}") - result += f"{'\n'.join(result_brailleTables)}\n" + result += "\n".join(result_brailleTables) + "\n" with codecs.open(out, "w", "utf-8") as f: f.write(result) From db1de6ddbdcb7fef3101587c5be3a0efdcad412a Mon Sep 17 00:00:00 2001 From: Johnson Murphy Date: Thu, 16 May 2024 12:24:14 +0800 Subject: [PATCH 215/362] Upgrade python version to 3.11 Signed-off-by: Johnson Murphy --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 9b97cd9..2ef9652 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -24,7 +24,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 cache: 'pip' - name: Install dependencies From 49c3a07aeebea20c04a420265926c68561042639 Mon Sep 17 00:00:00 2001 From: Johnson Murphy Date: Thu, 16 May 2024 12:35:07 +0800 Subject: [PATCH 216/362] fixed a bug of nested double quotes Signed-off-by: Johnson Murphy --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 36804f1..38a4e62 100644 --- a/sconstruct +++ b/sconstruct @@ -210,7 +210,7 @@ def generateTranslatedManifest(source, language, out): for table in buildVars.brailleTables.keys(): result_brailleTables.append(f"[[{table}]]") # Fetch display name only. - result_brailleTables.append(f"displayName = {buildVars.brailleTables[table]["displayName"]}") + result_brailleTables.append(f"displayName = {buildVars.brailleTables[table]['displayName']}") result += "\n".join(result_brailleTables) + "\n" with codecs.open(out, "w", "utf-8") as f: f.write(result) From a1e8e982209b54072c0f9a959f30491d4974efe2 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 29 Jun 2024 09:52:35 -0600 Subject: [PATCH 217/362] pyproject.toml: add Ruff section - first step toward replacing Flake8 with Ruff. Re #41. Flake8-tabs is unmaintained. In order to use Flake8-tabs, Flake8 4.0.1 or earlier must be used, meaning no newer Python features will not be supported. Therefore, replace Flake8 with Ruff (Python linter written in Rust), and as a first step, add pyproject.toml with add-on template version of Ruff configuration added. --- pyproject.toml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f71a8e6 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,34 @@ +[tool.ruff] +line-length = 110 + +builtins = [ + # translation lookup + "_", + # translation lookup + "ngettext", + # translation lookup + "pgettext", + # translation lookup + "npgettext", +] + +include = [ + "*.py", +] + +exclude = [ + ".git", + "__pycache__", +] + +[tool.ruff.format] +indent-style = "tab" + +[tool.ruff.lint.mccabe] +max-complexity = 15 + +[tool.ruff.lint] +ignore = [ + # indentation contains tabs + "W191", +] From 27b8fda4b48dd6f7c909bf355df298ec25c46e21 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 29 Jun 2024 09:54:42 -0600 Subject: [PATCH 218/362] SConstruct: mention Ruff alongside Flake8. Re #41 --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 38a4e62..b08751d 100644 --- a/sconstruct +++ b/sconstruct @@ -12,7 +12,7 @@ import sys # While names imported below are available by default in every SConscript # Linters aren't aware about them. -# To avoid Flake8 F821 warnings about them they are imported explicitly. +# To avoid Flake8/Ruff F821 warnings about them they are imported explicitly. # When using other Scons functions please add them to the line below. from SCons.Script import BoolVariable, Builder, Copy, Environment, Variables, EnsurePythonVersion # NOQA: E501, F401 From 0ac9d56e5400139156ad7f37859e7497353b7056 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 29 Jun 2024 10:02:24 -0600 Subject: [PATCH 219/362] Readme: mention Ruff alongside Flake8 (for now). Fixes #41 --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 332f063..ad65145 100644 --- a/readme.md +++ b/readme.md @@ -34,6 +34,7 @@ This template provides the following features you can use during NVDA add-on dev In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): * Flake8 (flake8.ini): a base configuration file for Flake8 linting tool based on NVDA's own Flake8 configuration file. +* Ruff (pyproject.toml/tool.ruff sections): a Python linter written in Rust. Sections starting with tool.ruff house configuration options for Ruff. * Configuration for VS Code. It requires NVDA's repo at the same level as the add-on folder containing your actual source files, with prepared source code (`scons source`). preparing the source code is a step in the instructions for building NVDA itself, see [The NVDA Repository](https://github.com/nvaccess/nvda) for details. * Place the .vscode in this repo within the addon folder, where your add-on source files (will) reside. The settings file within this folder assumes the NVDA repository is within the parent folder of this folder. If your addon folder is within the addonTemplate folder, then your NVDA repository folder needs to also be within the addonTemplate folder, or the source will not be found. * Open the addon folder in VS Code. This should initialize VS Code with the correct settings and provide you with code completion and other VS Code features. @@ -134,7 +135,8 @@ Note: you must fill out this dictionary if at least one custom braille table is The template includes configuration files for use with additional tools such as linters. These include: -* Flake8 (flake8.ini): a Python code linter (3.7.9 or later, can be installed with PIP). +* Flake8 (flake8.ini): a Python code linter (4.0.1, can be installed with PIP). +* Ruff (pyproject.toml): a Python linter written in Rust (0.4.10 or later, can be installed with PIP). Read the documentation for the tools you wish to use when building and developing add-ons. From 728260aaecab4835d9e4df38427a65a98dcd4c5d Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 29 Jun 2024 10:15:17 -0600 Subject: [PATCH 220/362] VS Code config: replace Flake8 with Ruff --- .vscode/extensions.json | 2 +- .vscode/settings.json | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 514e061..854ca85 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -6,7 +6,7 @@ "ms-python.python", "ms-python.vscode-pylance", "redhat.vscode-yaml", - "ms-python.flake8" + "charliermarsh.ruff" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [] diff --git a/.vscode/settings.json b/.vscode/settings.json index 6126d28..057f5a3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,5 @@ { "editor.accessibilitySupport": "on", - "flake8.args": [ - "--config=flake8.ini" - ], - "flake8.importStrategy": "fromEnvironment", "python.autoComplete.extraPaths": [ "../nvda/source", "../nvda/miscDeps/python" From 205fb167780abffa49d0565369c65f230302d579 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 29 Jun 2024 10:16:39 -0600 Subject: [PATCH 221/362] Flake8: ini file removed (replaced with Ruff) --- flake8.ini | 45 --------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 flake8.ini diff --git a/flake8.ini b/flake8.ini deleted file mode 100644 index cb731d8..0000000 --- a/flake8.ini +++ /dev/null @@ -1,45 +0,0 @@ -# Custom Flake8 configuration for community add-on template -# Based on NVDA's Flake8 configuration with modifications for the basic add-on template (edited by Joseph Lee) - -[flake8] - -# Plugins -use-flake8-tabs = True -# Not all checks are replaced by flake8-tabs, however, pycodestyle is still not compatible with tabs. -use-pycodestyle-indent = False -continuation-style = hanging -## The following are replaced by flake8-tabs plugin, reported as ET codes rather than E codes. -# E121, E122, E123, E126, E127, E128, -## The following (all disabled) are not replaced by flake8-tabs, -# E124 - Requires mixing spaces and tabs: Closing bracket does not match visual indentation. -# E125 - Does not take tabs into consideration: Continuation line with same indent as next logical line. -# E129 - Requires mixing spaces and tabs: Visually indented line with same indent as next logical line -# E131 - Requires mixing spaces and tabs: Continuation line unaligned for hanging indent -# E133 - Our preference handled by ET126: Closing bracket is missing indentation - - -# Reporting -statistics = True -doctests = True -show-source = True - -# Options -max-complexity = 15 -max-line-length = 110 -# Final bracket should match indentation of the start of the line of the opening bracket -hang-closing = False - -ignore = - ET113, # use of alignment as indentation, but option continuation-style=hanging does not permit this - W191, # indentation contains tabs - W503, # line break before binary operator. We want W504(line break after binary operator) - -builtins = # inform flake8 about functions we consider built-in. - _, # translation lookup - ngettext, # translation lookup - pgettext, # translation lookup - npgettext, # translation lookup - -exclude = # don't bother looking in the following subdirectories / files. - .git, - __pycache__, From 9a73405d7b690689eaed668c64d3839658cbf596 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 29 Jun 2024 10:17:44 -0600 Subject: [PATCH 222/362] SConstruct: remove Flake8 mention --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index b08751d..478b456 100644 --- a/sconstruct +++ b/sconstruct @@ -12,7 +12,7 @@ import sys # While names imported below are available by default in every SConscript # Linters aren't aware about them. -# To avoid Flake8/Ruff F821 warnings about them they are imported explicitly. +# To avoid Ruff F821 warnings about them they are imported explicitly. # When using other Scons functions please add them to the line below. from SCons.Script import BoolVariable, Builder, Copy, Environment, Variables, EnsurePythonVersion # NOQA: E501, F401 From 04c10368a55d023279acfd5cfe41dd71a0579447 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 29 Jun 2024 10:18:22 -0600 Subject: [PATCH 223/362] Readme: remove Flake8 mentions --- readme.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/readme.md b/readme.md index ad65145..e4f52b1 100644 --- a/readme.md +++ b/readme.md @@ -33,7 +33,6 @@ This template provides the following features you can use during NVDA add-on dev In addition, this template includes configuration files for the following tools for use in add-on development and testing (see "additional tools" section for details): -* Flake8 (flake8.ini): a base configuration file for Flake8 linting tool based on NVDA's own Flake8 configuration file. * Ruff (pyproject.toml/tool.ruff sections): a Python linter written in Rust. Sections starting with tool.ruff house configuration options for Ruff. * Configuration for VS Code. It requires NVDA's repo at the same level as the add-on folder containing your actual source files, with prepared source code (`scons source`). preparing the source code is a step in the instructions for building NVDA itself, see [The NVDA Repository](https://github.com/nvaccess/nvda) for details. * Place the .vscode in this repo within the addon folder, where your add-on source files (will) reside. The settings file within this folder assumes the NVDA repository is within the parent folder of this folder. If your addon folder is within the addonTemplate folder, then your NVDA repository folder needs to also be within the addonTemplate folder, or the source will not be found. @@ -135,7 +134,6 @@ Note: you must fill out this dictionary if at least one custom braille table is The template includes configuration files for use with additional tools such as linters. These include: -* Flake8 (flake8.ini): a Python code linter (4.0.1, can be installed with PIP). * Ruff (pyproject.toml): a Python linter written in Rust (0.4.10 or later, can be installed with PIP). Read the documentation for the tools you wish to use when building and developing add-ons. From 1908b552009e7d0123e013482ddde8c7865ddcae Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 7 Jul 2024 13:48:51 -0600 Subject: [PATCH 224/362] pyproject: add sconstruct file to scope of Ruff lint --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index f71a8e6..b6af16f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ builtins = [ include = [ "*.py", + "sconstruct", ] exclude = [ From f3fc4d50fae2dab1ddc27ee1ae3f159dc8930c10 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 7 Jul 2024 13:49:22 -0600 Subject: [PATCH 225/362] pyproject/sconstruct: ignore F821 (attribute definition) error --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index b6af16f..4d76bfe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,3 +33,8 @@ ignore = [ # indentation contains tabs "W191", ] + +[tool.ruff.lint.per-file-ignores] +# sconstruct contains many inbuilt functions not recognised by the lint, +# so ignore F821. +"sconstruct" = ["F821"] From 4ca17c1e13094fa3f2715f74f30de593166994c6 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 7 Jul 2024 13:59:06 -0600 Subject: [PATCH 226/362] SConstruct: remove Ruff lint F821 notes as pyproject.toml will keep F821 in mind (scons functions) --- sconstruct | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sconstruct b/sconstruct index 478b456..cb3639e 100644 --- a/sconstruct +++ b/sconstruct @@ -10,12 +10,6 @@ import os.path import zipfile import sys -# While names imported below are available by default in every SConscript -# Linters aren't aware about them. -# To avoid Ruff F821 warnings about them they are imported explicitly. -# When using other Scons functions please add them to the line below. -from SCons.Script import BoolVariable, Builder, Copy, Environment, Variables, EnsurePythonVersion # NOQA: E501, F401 - # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. EnsurePythonVersion(3, 10) From c8bfb499f7d5b55e5013e74d4bf2296fccfe61e4 Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Sat, 17 Aug 2024 15:25:03 +0200 Subject: [PATCH 227/362] Add support for 2024.3 symbol dictionaries --- buildVars.py | 9 +++++++++ readme.md | 14 +++++++++++++- sconstruct | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index a95a1c5..29d781f 100644 --- a/buildVars.py +++ b/buildVars.py @@ -87,3 +87,12 @@ def _(arg): # output (shown in output table list), # input (shown in input table list). brailleTables = {} + +# Custom speech symbol dictionaries +# Symbol dictionary files reside in the locale folder, e.g. `locale\en`, and are named `symbols-.dic`. +# If your add-on includes custom speech symbol dictionaries (most will not), fill out this dictionary. +# Each key is the name of the dictionary, +# with keys inside recording the following attributes: +# displayName (name of the table shown to users and translatable), +# mandatory (True when always enabled, False when not. +symbolDictionaries = {} diff --git a/readme.md b/readme.md index e4f52b1..8d0af14 100644 --- a/readme.md +++ b/readme.md @@ -105,7 +105,10 @@ In addition, the following information must be filled out (not used in the manif ##### Custom add-on information -In addition to the core manifest data, custom add-on information can be specified. As of 2024, the template supports generation of custom braille translation tables. Information on custom braille tables must be specified in buildVars under `braileTables` dictionary as follows: +In addition to the core manifest data, custom add-on information can be specified. + +###### Braille translation tables +Information on custom braille tables must be specified in buildVars under `brailleTables` dictionary as follows: * Table name (string key for a nested dictionary): each `brailleTables` entry is a filename for the included custom braille table placed in `brailleTables` folder inside `addon` folder. This nested dictionary should specify: * displayName (string): the name of the table shown to users and is translatable. @@ -115,6 +118,15 @@ In addition to the core manifest data, custom add-on information can be specifie Note: you must fill out this dictionary if at least one custom braille table is included in the add-on. If not, leave the dictionary empty. +###### SPeech symbol dictionaries +Information on custom symbol dictionaries must be specified in buildVars under `symbolDictionaries` dictionary as follows: + +* Dictionary name (string key for a nested dictionary): each `symbolDictionaries` entry is a name for the included custom symbol dictionary placed in `locale\` folder inside `addon` folder. The file is named `symbols-.dic`. This nested dictionary should specify: + * displayName (string): the name of the dictionary shown to users and is translatable. + * mandatory (True/False): Always enabled (True) or optional and visible in the GUI (False) + +Note: you must fill out this dictionary if at least one custom symbol dictionary is included in the add-on. If not, leave the dictionary empty. + ### To manage documentation files for your addon: 1. Copy the `readme.md` file for your add-on to the first created folder, where you copied `buildVars.py`. You can also copy `style.css` to improve the presentation of HTML documents. diff --git a/sconstruct b/sconstruct index cb3639e..af99243 100644 --- a/sconstruct +++ b/sconstruct @@ -185,6 +185,16 @@ def generateManifest(source, dest): for key, val in buildVars.brailleTables[table].items(): manifest_brailleTables.append(f"{key} = {val}") manifest += "\n".join(manifest_brailleTables) + "\n" + + # Custom speech symbol dictionaries + if getattr(buildVars, "symbolDictionaries", {}): + manifest_symbolDictionaries = ["\n[symbolDictionaries]"] + for dictionary in buildVars.symbolDictionaries.keys(): + manifest_symbolDictionaries.append(f"[[{dictionary}]]") + for key, val in buildVars.symbolDictionaries[dictionary].items(): + manifest_symbolDictionaries.append(f"{key} = {val}") + manifest += "\n".join(manifest_symbolDictionaries) + "\n" + with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) @@ -206,6 +216,16 @@ def generateTranslatedManifest(source, language, out): # Fetch display name only. result_brailleTables.append(f"displayName = {buildVars.brailleTables[table]['displayName']}") result += "\n".join(result_brailleTables) + "\n" + + # Custom speech symbol dictionaries + if getattr(buildVars, "symbolDictionaries", {}): + result_symbolDictionaries = ["\n[symbolDictionaries]"] + for dictionary in buildVars.symbolDictionaries.keys(): + result_symbolDictionaries.append(f"[[{dictionary}]]") + # Fetch display name only. + result_symbolDictionaries.append(f"displayName = {buildVars.symbolDictionaries[dictionary]['displayName']}") + result += "\n".join(result_symbolDictionaries) + "\n" + with codecs.open(out, "w", "utf-8") as f: f.write(result) From 75123e2fb14ea0f0cc61c9312d6417acfacda48c Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Sat, 17 Aug 2024 15:50:39 +0200 Subject: [PATCH 228/362] Fix translation of displayName --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index af99243..8acd430 100644 --- a/sconstruct +++ b/sconstruct @@ -214,7 +214,7 @@ def generateTranslatedManifest(source, language, out): for table in buildVars.brailleTables.keys(): result_brailleTables.append(f"[[{table}]]") # Fetch display name only. - result_brailleTables.append(f"displayName = {buildVars.brailleTables[table]['displayName']}") + result_brailleTables.append(f"displayName = {_(buildVars.brailleTables[table]['displayName'])}") result += "\n".join(result_brailleTables) + "\n" # Custom speech symbol dictionaries @@ -223,7 +223,7 @@ def generateTranslatedManifest(source, language, out): for dictionary in buildVars.symbolDictionaries.keys(): result_symbolDictionaries.append(f"[[{dictionary}]]") # Fetch display name only. - result_symbolDictionaries.append(f"displayName = {buildVars.symbolDictionaries[dictionary]['displayName']}") + result_symbolDictionaries.append(f"displayName = {_(buildVars.symbolDictionaries[dictionary]['displayName'])}") result += "\n".join(result_symbolDictionaries) + "\n" with codecs.open(out, "w", "utf-8") as f: From 6583ed7a38663295ed22d3886d0b0f8dfd059146 Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter <3049216+LeonarddeR@users.noreply.github.com> Date: Mon, 19 Aug 2024 07:54:56 +0200 Subject: [PATCH 229/362] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Noelia Ruiz Martínez --- buildVars.py | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index 29d781f..d813367 100644 --- a/buildVars.py +++ b/buildVars.py @@ -93,6 +93,6 @@ def _(arg): # If your add-on includes custom speech symbol dictionaries (most will not), fill out this dictionary. # Each key is the name of the dictionary, # with keys inside recording the following attributes: -# displayName (name of the table shown to users and translatable), +# displayName (name of the speech dictionary shown to users and translatable), # mandatory (True when always enabled, False when not. symbolDictionaries = {} diff --git a/readme.md b/readme.md index 8d0af14..e6e43f0 100644 --- a/readme.md +++ b/readme.md @@ -118,7 +118,7 @@ Information on custom braille tables must be specified in buildVars under `brail Note: you must fill out this dictionary if at least one custom braille table is included in the add-on. If not, leave the dictionary empty. -###### SPeech symbol dictionaries +###### Speech symbol dictionaries Information on custom symbol dictionaries must be specified in buildVars under `symbolDictionaries` dictionary as follows: * Dictionary name (string key for a nested dictionary): each `symbolDictionaries` entry is a name for the included custom symbol dictionary placed in `locale\` folder inside `addon` folder. The file is named `symbols-.dic`. This nested dictionary should specify: From 12a007f6935ffed5f68951d9d6e12d94e3e0d109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Sun, 6 Oct 2024 13:36:38 +0200 Subject: [PATCH 230/362] Added support for Dependabot, which will create a pull request whenever a new version of a GitHub action is available. This will ensure that template is always up do date with latest actions --- .github/dependabot.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..50617c0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + # Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.) + directory: "/" + schedule: + interval: "weekly" + groups: + actions-minor: + update-types: + - minor + - patch From d54120142fe3699178f3276b7e6c2ae4a91b4130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Sun, 6 Oct 2024 13:48:37 +0200 Subject: [PATCH 231/362] Include a changelog file which will be part of the release body when GitHub workflow is triggered. Add-on SHA256 sum will always be printed at the end of the file --- .github/workflows/build_addon.yml | 3 +++ changelog.md | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 changelog.md diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 2ef9652..0dc81f4 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -55,10 +55,13 @@ jobs: uses: actions/download-artifact@v3 - name: Display structure of downloaded files run: ls -R + - name: Calculate sha256 + run: sha256sum packaged_addon/*.nvda-addon >> changelog.md - name: Release uses: softprops/action-gh-release@v1 with: files: packaged_addon/*.nvda-addon + body_path: changelog.md fail_on_unmatched_files: true prerelease: ${{ contains(github.ref, '-') }} diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..e0ad39a --- /dev/null +++ b/changelog.md @@ -0,0 +1,5 @@ +Use this file to explain what has changed in your add-on since the previous release. This will be included automatically in the release description when used with GitHub actions. + +Don't modify the following line, unless you also remove SHA256 sum calculation from the workflow. This line must be the last one in the file. + +SHA256: \ No newline at end of file From e9985ab22323f727c65d85025f9e5fd042a21f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Delicado=20Alcolea?= Date: Sun, 6 Oct 2024 14:02:42 +0200 Subject: [PATCH 232/362] Include a template for translators on each add-on release as part of the assets --- .github/workflows/build_addon.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 2ef9652..2450d1e 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -38,12 +38,14 @@ jobs: run: export SKIP=no-commit-to-branch; pre-commit run --all - name: building addon - run: scons + run: scons && scons pot - uses: actions/upload-artifact@v3 with: name: packaged_addon - path: ./*.nvda-addon + path: | + ./*.nvda-addon + ./*.pot upload_release: runs-on: ubuntu-latest @@ -59,6 +61,8 @@ jobs: - name: Release uses: softprops/action-gh-release@v1 with: - files: packaged_addon/*.nvda-addon + files: | + packaged_addon/*.nvda-addon + packaged_addon/*.pot fail_on_unmatched_files: true prerelease: ${{ contains(github.ref, '-') }} From ff581ae7849a176a39bfb330e411defc9909458d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:24:37 +0000 Subject: [PATCH 233/362] Bump actions/setup-python from 4 to 5 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 2450d1e..25b25e9 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -22,7 +22,7 @@ jobs: - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.11 cache: 'pip' From d342db5f538b00fddfd24d5b1e370fc4ec02bb1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:24:39 +0000 Subject: [PATCH 234/362] Bump actions/upload-artifact from 3 to 4 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 2450d1e..f0d273a 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -40,7 +40,7 @@ jobs: - name: building addon run: scons && scons pot - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: packaged_addon path: | From 9c951ff5213a9e728cfe64349a0af4ff1e474910 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:24:41 +0000 Subject: [PATCH 235/362] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 2450d1e..d78b9da 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt @@ -52,7 +52,7 @@ jobs: if: ${{ startsWith(github.ref, 'refs/tags/') }} needs: ["build"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: download releases files uses: actions/download-artifact@v3 - name: Display structure of downloaded files From 27e474d88722876f2ffb022058e3c905729c0b02 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:03:37 +0000 Subject: [PATCH 236/362] Bump softprops/action-gh-release from 1 to 2 Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 105f867..64a125c 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -61,7 +61,7 @@ jobs: run: sha256sum packaged_addon/*.nvda-addon >> changelog.md - name: Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: files: | packaged_addon/*.nvda-addon From 33d0464b84a42faa519e92e0663cd8485b61b28e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:03:46 +0000 Subject: [PATCH 237/362] Bump actions/download-artifact from 3 to 4 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 105f867..4603eee 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -54,7 +54,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: download releases files - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Display structure of downloaded files run: ls -R - name: Calculate sha256 From ec06b99f30fd4082c476397debdd160096f15225 Mon Sep 17 00:00:00 2001 From: hwf1324 <1398969445@qq.com> Date: Mon, 28 Oct 2024 14:08:47 +0800 Subject: [PATCH 238/362] changeSHA --- .github/workflows/build_addon.yml | 4 +++- changelog.md | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 108fa36..1e56dcc 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -58,7 +58,9 @@ jobs: - name: Display structure of downloaded files run: ls -R - name: Calculate sha256 - run: sha256sum packaged_addon/*.nvda-addon >> changelog.md + run: | + echo -e "\nSHA256: " >> changelog.md + sha256sum packaged_addon/*.nvda-addon >> changelog.md - name: Release uses: softprops/action-gh-release@v2 diff --git a/changelog.md b/changelog.md index e0ad39a..d07b337 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1 @@ Use this file to explain what has changed in your add-on since the previous release. This will be included automatically in the release description when used with GitHub actions. - -Don't modify the following line, unless you also remove SHA256 sum calculation from the workflow. This line must be the last one in the file. - -SHA256: \ No newline at end of file From fc901de81e0270afc120ad48fcdb745c22961ba4 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 5 Nov 2024 12:21:32 -0700 Subject: [PATCH 239/362] SConstruct (Ruff): format the module to align with NVDA Core --- sconstruct | 87 +++++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/sconstruct b/sconstruct index 8acd430..38ee75d 100644 --- a/sconstruct +++ b/sconstruct @@ -21,12 +21,15 @@ import buildVars # NOQA: E402 def md2html(source, dest): import markdown + # Use extensions if defined. mdExtensions = buildVars.markdownExtensions - lang = os.path.basename(os.path.dirname(source)).replace('_', '-') + lang = os.path.basename(os.path.dirname(source)).replace("_", "-") localeLang = os.path.basename(os.path.dirname(source)) try: - _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).gettext + _ = gettext.translation( + "nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang] + ).gettext summary = _(buildVars.addon_info["addon_summary"]) except Exception: summary = buildVars.addon_info["addon_summary"] @@ -34,8 +37,8 @@ def md2html(source, dest): addonSummary=summary, addonVersion=buildVars.addon_info["addon_version"] ) headerDic = { - "[[!meta title=\"": "# ", - "\"]]": " #", + '[[!meta title="': "# ", + '"]]': " #", } with codecs.open(source, "r", "utf-8") as f: mdText = f.read() @@ -43,18 +46,19 @@ def md2html(source, dest): mdText = mdText.replace(k, v, 1) htmlText = markdown.markdown(mdText, extensions=mdExtensions) # Optimization: build resulting HTML text in one go instead of writing parts separately. - docText = "\n".join([ - "", - f"", - "", - "" - "", - "", - f"{title}", - "\n", - htmlText, - "\n" - ]) + docText = "\n".join( + [ + "", + f'', + "", + '' '', + '', + f"{title}", + "\n", + htmlText, + "\n", + ] + ) with codecs.open(dest, "w", "utf-8") as f: f.write(docText) @@ -66,10 +70,10 @@ def mdTool(env): ) mdBuilder = env.Builder( action=mdAction, - suffix='.html', - src_suffix='.md', + suffix=".html", + src_suffix=".md", ) - env['BUILDERS']['markdown'] = mdBuilder + env["BUILDERS"]["markdown"] = mdBuilder def validateVersionNumber(key, val, env): @@ -90,11 +94,12 @@ vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0 vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) -env = Environment(variables=vars, ENV=os.environ, tools=['gettexttool', mdTool]) +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", mdTool]) env.Append(**buildVars.addon_info) if env["dev"]: import datetime + buildDate = datetime.datetime.now() year, month, day = str(buildDate.year), str(buildDate.month), str(buildDate.day) versionTimestamp = "".join([year, month.zfill(2), day.zfill(2)]) @@ -115,7 +120,7 @@ addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") def addonGenerator(target, source, env, for_signature): action = env.Action( lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, - lambda target, source, env: f"Generating Addon {target[0]}" + lambda target, source, env: f"Generating Addon {target[0]}", ) return action @@ -123,7 +128,7 @@ def addonGenerator(target, source, env, for_signature): def manifestGenerator(target, source, env, for_signature): action = env.Action( lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, - lambda target, source, env: f"Generating manifest {target[0]}" + lambda target, source, env: f"Generating manifest {target[0]}", ) return action @@ -132,15 +137,16 @@ def translatedManifestGenerator(target, source, env, for_signature): dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) lang = os.path.basename(dir) action = env.Action( - lambda target, source, env: generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None, - lambda target, source, env: f"Generating translated manifest {target[0]}" + lambda target, source, env: generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) + and None, + lambda target, source, env: f"Generating translated manifest {target[0]}", ) return action -env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) -env['BUILDERS']['NVDAManifest'] = Builder(generator=manifestGenerator) -env['BUILDERS']['NVDATranslatedManifest'] = Builder(generator=translatedManifestGenerator) +env["BUILDERS"]["NVDAAddon"] = Builder(generator=addonGenerator) +env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) +env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) def createAddonHelp(dir): @@ -156,9 +162,9 @@ def createAddonHelp(dir): def createAddonBundleFromPath(path, dest): - """ Creates a bundle from a directory that contains an addon manifest file.""" + """Creates a bundle from a directory that contains an addon manifest file.""" basedir = os.path.abspath(path) - with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as z: + with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as z: # FIXME: the include/exclude feature may or may not be useful. Also python files can be pre-compiled. for dir, dirnames, filenames in os.walk(basedir): relativePath = os.path.relpath(dir, basedir) @@ -223,7 +229,9 @@ def generateTranslatedManifest(source, language, out): for dictionary in buildVars.symbolDictionaries.keys(): result_symbolDictionaries.append(f"[[{dictionary}]]") # Fetch display name only. - result_symbolDictionaries.append(f"displayName = {_(buildVars.symbolDictionaries[dictionary]['displayName'])}") + result_symbolDictionaries.append( + f"displayName = {_(buildVars.symbolDictionaries[dictionary]['displayName'])}" + ) result += "\n".join(result_symbolDictionaries) + "\n" with codecs.open(out, "w", "utf-8") as f: @@ -234,7 +242,7 @@ def expandGlobs(files): return [f for pattern in files for f in env.Glob(pattern)] -addon = env.NVDAAddon(addonFile, env.Dir('addon')) +addon = env.NVDAAddon(addonFile, env.Dir("addon")) langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] @@ -244,8 +252,7 @@ for dir in langDirs: moFile = env.gettextMoFile(poFile) env.Depends(moFile, poFile) translatedManifest = env.NVDATranslatedManifest( - dir.File("manifest.ini"), - [moFile, os.path.join("manifest-translated.ini.tpl")] + dir.File("manifest.ini"), [moFile, os.path.join("manifest-translated.ini.tpl")] ) env.Depends(translatedManifest, ["buildVars.py"]) env.Depends(addon, [translatedManifest, moFile]) @@ -257,7 +264,7 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager createAddonHelp("addon") -for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): +for mdFile in env.Glob(os.path.join("addon", "doc", "*", "*.md")): htmlFile = env.markdown(mdFile) try: # It is possible that no moFile was set, because an add-on has no translations. moFile @@ -270,16 +277,16 @@ for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) gettextvars = { - 'gettext_package_bugs_address': 'nvda-translations@groups.io', - 'gettext_package_name': buildVars.addon_info['addon_name'], - 'gettext_package_version': buildVars.addon_info['addon_version'] + "gettext_package_bugs_address": "nvda-translations@groups.io", + "gettext_package_name": buildVars.addon_info["addon_name"], + "gettext_package_version": buildVars.addon_info["addon_version"], } pot = env.gettextPotFile("${addon_name}.pot", i18nFiles, **gettextvars) -env.Alias('pot', pot) +env.Alias("pot", pot) env.Depends(pot, i18nFiles) mergePot = env.gettextMergePotFile("${addon_name}-merge.pot", i18nFiles, **gettextvars) -env.Alias('mergePot', mergePot) +env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path @@ -289,4 +296,4 @@ env.Depends(manifest, "buildVars.py") env.Depends(addon, manifest) env.Default(addon) -env.Clean(addon, ['.sconsign.dblite', 'addon/doc/' + buildVars.baseLanguage + '/']) +env.Clean(addon, [".sconsign.dblite", "addon/doc/" + buildVars.baseLanguage + "/"]) From de41dd2baaade8939c81baca091999321381cb6d Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 5 Nov 2024 12:21:47 -0700 Subject: [PATCH 240/362] Gettext Site tools (Ruff): format the module --- site_scons/site_tools/gettexttool/__init__.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index db9a009..900f8dc 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -1,4 +1,4 @@ -""" This tool allows generation of gettext .mo compiled files, pot files from source code files +"""This tool allows generation of gettext .mo compiled files, pot files from source code files and pot files for merging. Three new builders are added into the constructed environment: @@ -15,6 +15,7 @@ """ + from SCons.Action import Action @@ -36,20 +37,19 @@ def generate(env): env.SetDefault(gettext_package_name="") env.SetDefault(gettext_package_version="") - env['BUILDERS']['gettextMoFile'] = env.Builder( + env["BUILDERS"]["gettextMoFile"] = env.Builder( action=Action("msgfmt -o $TARGET $SOURCE", "Compiling translation $SOURCE"), suffix=".mo", - src_suffix=".po" + src_suffix=".po", ) - env['BUILDERS']['gettextPotFile'] = env.Builder( - action=Action("xgettext " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), - suffix=".pot") + env["BUILDERS"]["gettextPotFile"] = env.Builder( + action=Action("xgettext " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), suffix=".pot" + ) - env['BUILDERS']['gettextMergePotFile'] = env.Builder( + env["BUILDERS"]["gettextMergePotFile"] = env.Builder( action=Action( - "xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, - "Generating pot file $TARGET" + "xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET" ), - suffix=".pot" + suffix=".pot", ) From 2f4ba1ec0ab7eb3a0bbb8fb7a9be0c6459ac09e0 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 14 Nov 2024 04:22:31 -0700 Subject: [PATCH 241/362] Add-on template/build vars: add a note on editing .gitignore files when changing base language. Closes #53 --- buildVars.py | 1 + 1 file changed, 1 insertion(+) diff --git a/buildVars.py b/buildVars.py index d813367..c62935e 100644 --- a/buildVars.py +++ b/buildVars.py @@ -69,6 +69,7 @@ def _(arg): # Base language for the NVDA add-on # If your add-on is written in a language other than english, modify this variable. # For example, set baseLanguage to "es" if your add-on is primarily written in spanish. +# You must also edit .gitignore file to specify base language files to be ignored. baseLanguage = "en" # Markdown extensions for add-on documentation From 3b22bfa813dc77c5cd2518e6ebe39f55493da62e Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 20 Nov 2024 05:10:15 -0700 Subject: [PATCH 242/362] SConstruct: reformat via Ruff --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index e7ca0b5..9b576af 100644 --- a/sconstruct +++ b/sconstruct @@ -266,7 +266,7 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager createAddonHelp("addon") -for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): +for mdFile in env.Glob(os.path.join("addon", "doc", "*", "*.md")): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. lang = os.path.basename(os.path.dirname(mdFile.get_abspath())) From 4e80d7b822185fbd9acc863f4a811082ec397fed Mon Sep 17 00:00:00 2001 From: hwf1324 <1398969445@qq.com> Date: Thu, 2 Jan 2025 21:52:06 +0800 Subject: [PATCH 243/362] The meta elements in the generated HTML are on separate lines. --- sconstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 9b576af..38d2483 100644 --- a/sconstruct +++ b/sconstruct @@ -51,7 +51,8 @@ def md2html(source, dest): "", f'', "", - '' '', + '', + '', '', f"{title}", "\n", From 5584c62b45e1a89f9e6f245b1a069769942f68e2 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 2 Jan 2025 08:23:21 -0700 Subject: [PATCH 244/362] Readme and SConstruct: update copyright years, update dependency versions --- readme.md | 14 ++++++++------ sconstruct | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index e6e43f0..b8613f9 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ For details about NVDA add-on development, please see the [NVDA Add-on Developme The NVDA add-on development/discussion list [is here](https://nvda-addons.groups.io/g/nvda-addons) Information specific to NV Access add-on store [can be found here](https://github.com/nvaccess/addon-datastore). -Copyright (C) 2012-2024 NVDA Add-on team contributors. +Copyright (C) 2012-2025 NVDA Add-on team contributors. This package is distributed under the terms of the GNU General Public License, version 2 or later. Please see the file COPYING.txt for further details. @@ -35,8 +35,8 @@ In addition, this template includes configuration files for the following tools * Ruff (pyproject.toml/tool.ruff sections): a Python linter written in Rust. Sections starting with tool.ruff house configuration options for Ruff. * Configuration for VS Code. It requires NVDA's repo at the same level as the add-on folder containing your actual source files, with prepared source code (`scons source`). preparing the source code is a step in the instructions for building NVDA itself, see [The NVDA Repository](https://github.com/nvaccess/nvda) for details. - * Place the .vscode in this repo within the addon folder, where your add-on source files (will) reside. The settings file within this folder assumes the NVDA repository is within the parent folder of this folder. If your addon folder is within the addonTemplate folder, then your NVDA repository folder needs to also be within the addonTemplate folder, or the source will not be found. - * Open the addon folder in VS Code. This should initialize VS Code with the correct settings and provide you with code completion and other VS Code features. + * Place the .vscode in this repo within the addon folder, where your add-on source files (will) reside. The settings file within this folder assumes the NVDA repository is within the parent folder of this folder. If your addon folder is within the addonTemplate folder, then your NVDA repository folder needs to also be within the addonTemplate folder, or the source will not be found. + * Open the addon folder in VS Code. This should initialize VS Code with the correct settings and provide you with code completion and other VS Code features. * Press `control+shift+m` after saving a file to search for problems. * Use arrow and tab keys for the autocompletion feature. * Press `control+shift+p` to open the commands palette and search for recommended extensions to install or check if they are installed. @@ -46,9 +46,9 @@ In addition, this template includes configuration files for the following tools You need the following software to use this code for your NVDA add-on development and packaging: * a Python distribution (3.11 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.11. -* Scons - [Website](https://www.scons.org/) - version 4.5.2 or later. You can install it via PIP. +* Scons - [Website](https://www.scons.org/) - version 4.8.1 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). -* Markdown 3.3.0 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. +* Markdown 3.7 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. Note, that you may not need these tools in a local build environment, if you are using [Appveyor](https://appveyor.com/) or [GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions), to build and package your add-ons. @@ -86,7 +86,7 @@ and file: An add-on manifest generated manually or via `buildVars.py` must include the following information: -* Name (string): a unique identifier for the add-on. It must use camel case (e.g. someModule). This is also used as part of add-on store to identify the add-on uniquely. +* Name (string): a unique internal identifier for the add-on. It must use camel case (e.g. someModule). This is also used as part of add-on store to identify the add-on uniquely. * Summary (string): name as shown on NVDA's Add-on store. * Description (string): a short detailed description about the add-on. * Version (string), ideally number.number with an optional third number, denoting major.minor.patch. @@ -108,6 +108,7 @@ In addition, the following information must be filled out (not used in the manif In addition to the core manifest data, custom add-on information can be specified. ###### Braille translation tables + Information on custom braille tables must be specified in buildVars under `brailleTables` dictionary as follows: * Table name (string key for a nested dictionary): each `brailleTables` entry is a filename for the included custom braille table placed in `brailleTables` folder inside `addon` folder. This nested dictionary should specify: @@ -119,6 +120,7 @@ Information on custom braille tables must be specified in buildVars under `brail Note: you must fill out this dictionary if at least one custom braille table is included in the add-on. If not, leave the dictionary empty. ###### Speech symbol dictionaries + Information on custom symbol dictionaries must be specified in buildVars under `symbolDictionaries` dictionary as follows: * Dictionary name (string key for a nested dictionary): each `symbolDictionaries` entry is a name for the included custom symbol dictionary placed in `locale\` folder inside `addon` folder. The file is named `symbols-.dic`. This nested dictionary should specify: diff --git a/sconstruct b/sconstruct index 38d2483..369b1f7 100644 --- a/sconstruct +++ b/sconstruct @@ -1,5 +1,5 @@ # NVDA add-on template SCONSTRUCT file -# Copyright (C) 2012-2024 Rui Batista, Noelia Martinez, Joseph Lee +# Copyright (C) 2012-2025 Rui Batista, Noelia Martinez, Joseph Lee # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. From ac411c428e1343f8366811b0785c5a1bb5a9aa1c Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 2 Jan 2025 08:27:49 -0700 Subject: [PATCH 245/362] Add-on template: remove template-based NV Access add-on store json file as it is generated when submitting the add-on to the store --- _template_addon_release.json | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 _template_addon_release.json diff --git a/_template_addon_release.json b/_template_addon_release.json deleted file mode 100644 index c6d3a5f..0000000 --- a/_template_addon_release.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "addonId": "easyAddonTech.XYZ", - "addonVersionNumber": { - "major": 21, - "minor": 6, - "patch": 0 - }, - "addonVersionName": "21.06", - "displayName": "My addon", - "publisher": "easyAddonTech", - "description": "Makes doing XYZ easier", - "homepage": "https://github.com/nvaccess/addon-datastore", - "minNVDAVersion": { - "major": 2019, - "minor": 3, - "patch": 0 - }, - "lastTestedVersion": { - "major": 2020, - "minor": 4, - "patch": 0 - }, - "channel": "beta", - "URL": "https://github.com/nvaccess/addon-datastore/releases/download/v0.1.0/myAddon.nvda-addon", - "sha256": "69D84CA8899800A5575CE31798293CD4FEBAB1D734A07C2E51E56A28E0DF8C82", - "sourceURL": "https://github.com/nvaccess/addon-datastore/", - "license": "GPL v2", - "licenseURL": "https://github.com/nvaccess/addon-datastore/license.MD" -} From 3e124a499e118293913161578aa69f9d6bb29919 Mon Sep 17 00:00:00 2001 From: Tyler Spivey Date: Mon, 3 Feb 2025 08:05:11 -0800 Subject: [PATCH 246/362] Enable write permission when creating releases According to the [action-gh-release documentation](https://github.com/softprops/action-gh-release#permissions), write permission is required for contents. --- .github/workflows/build_addon.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 1e56dcc..1cf0f09 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -51,6 +51,8 @@ jobs: runs-on: ubuntu-latest if: ${{ startsWith(github.ref, 'refs/tags/') }} needs: ["build"] + permissions: + contents: write steps: - uses: actions/checkout@v4 - name: download releases files From c0aa5a6d66d562d5c43763fa7d84b1da2a7412d4 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 26 Feb 2025 06:28:20 -0700 Subject: [PATCH 247/362] BuildVars: add-ons manager -> add-on store, clarify that summary can be add-on title --- buildVars.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/buildVars.py b/buildVars.py index c62935e..ddc31f2 100644 --- a/buildVars.py +++ b/buildVars.py @@ -17,12 +17,12 @@ def _(arg): addon_info = { # add-on Name/identifier, internal for NVDA "addon_name": "addonTemplate", - # Add-on summary, usually the user visible name of the addon. - # Translators: Summary for this add-on - # to be shown on installation and add-on information found in Add-ons Manager. + # Add-on summary/title, usually the user visible name of the add-on + # Translators: Summary/title for this add-on + # to be shown on installation and add-on information found in add-on store "addon_summary": _("Add-on user visible name"), # Add-on description - # Translators: Long description to be shown for this add-on on add-on information from add-ons manager + # Translators: Long description to be shown for this add-on on add-on information from add-on store "addon_description": _("""Description for the add-on. It can span multiple lines."""), # version From cb03ab8915d29fdf1b18f3a2320045485f6d4b5b Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 26 Feb 2025 06:28:59 -0700 Subject: [PATCH 248/362] BuildVars: update minimum and last tesed version examples based on add-on store metadata (store minimum version is 2019.1.0) --- buildVars.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index ddc31f2..85f1e4a 100644 --- a/buildVars.py +++ b/buildVars.py @@ -35,9 +35,9 @@ def _(arg): "addon_sourceURL": None, # Documentation file name "addon_docFileName": "readme.html", - # Minimum NVDA version supported (e.g. "2018.3.0", minor version is optional) + # Minimum NVDA version supported (e.g. "2019.3.0", minor version is optional) "addon_minimumNVDAVersion": None, - # Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version) + # Last NVDA version supported/tested (e.g. "2024.4.0", ideally more recent than minimum version) "addon_lastTestedNVDAVersion": None, # Add-on update channel (default is None, denoting stable releases, # and for development releases, use "dev".) From eb4f6430dd88d1c0cf99277c02ba41f946938bea Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 12 Mar 2025 21:53:37 -0600 Subject: [PATCH 249/362] BuildVars, readme, sconstruct: remove extraneous whitespace --- buildVars.py | 2 +- readme.md | 2 +- sconstruct | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/buildVars.py b/buildVars.py index 85f1e4a..785c17c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -94,6 +94,6 @@ def _(arg): # If your add-on includes custom speech symbol dictionaries (most will not), fill out this dictionary. # Each key is the name of the dictionary, # with keys inside recording the following attributes: -# displayName (name of the speech dictionary shown to users and translatable), +# displayName (name of the speech dictionary shown to users and translatable), # mandatory (True when always enabled, False when not. symbolDictionaries = {} diff --git a/readme.md b/readme.md index b8613f9..9f72969 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ This package is distributed under the terms of the GNU General Public License, v [alekssamos](https://github.com/alekssamos/) added automatic package of add-ons through Github Actions. -For details about Github Actions please see the [Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). +For details about Github Actions, see the [Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). Copyright (C) 2022 alekssamos diff --git a/sconstruct b/sconstruct index 369b1f7..ac689d2 100644 --- a/sconstruct +++ b/sconstruct @@ -1,4 +1,4 @@ -# NVDA add-on template SCONSTRUCT file +# NVDA add-on template SCONSTRUCT file # Copyright (C) 2012-2025 Rui Batista, Noelia Martinez, Joseph Lee # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. From ba7c6574aec858f3345a05f5c09de7c41e719b5a Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 22 Jun 2025 14:39:32 -0600 Subject: [PATCH 250/362] Pyproject: add Pyright support. By default, Pyright rules will be reported and add-on authors can add bad rules with explanations to bad rules list in the end. For examples, see Emoticons and StationPlaylist add-ons. --- pyproject.toml | 121 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 4d76bfe..97189ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,3 +38,124 @@ ignore = [ # sconstruct contains many inbuilt functions not recognised by the lint, # so ignore F821. "sconstruct" = ["F821"] + +[tool.pyright] +pythonPlatform = "Windows" +typeCheckingMode = "strict" + +include = [ + "**/*.py", +] + +exclude = [ + "sconstruct", + ".git", + "__pycache__", + # When excluding concrete paths relative to a directory, + # not matching multiple folders by name e.g. `__pycache__`, + # paths are relative to the configuration file. +] + +# Tell pyright where to load python code from +extraPaths = [ + "./addon", +] + +# General config +analyzeUnannotatedFunctions = true +deprecateTypingAliases = true + +# Stricter typing +strictParameterNoneValue = true +strictListInference = true +strictDictionaryInference = true +strictSetInference = true + +# Compliant rules +reportAbstractUsage = true +reportArgumentType = true +reportAssertAlwaysTrue = true +reportAssertTypeFailure = true +reportAssignmentType = true +reportAttributeAccessIssue = true +reportCallInDefaultInitializer = true +reportCallIssue = true +reportConstantRedefinition = true +reportDuplicateImport = true +reportFunctionMemberAccess = true +reportGeneralTypeIssues = true +reportImplicitOverride = true +reportImplicitStringConcatenation = true +reportImportCycles = true +reportIncompatibleMethodOverride = true +reportIncompatibleVariableOverride = true +reportIncompleteStub = true +reportInconsistentConstructor = true +reportInconsistentOverload = true +reportIndexIssue = true +reportInvalidStringEscapeSequence = true +reportInvalidStubStatement = true +reportInvalidTypeArguments = true +reportInvalidTypeForm = true +reportInvalidTypeVarUse = true +reportMatchNotExhaustive = true +reportMissingImports = true +reportMissingModuleSource = true +reportMissingParameterType = true +reportMissingSuperCall = true +reportMissingTypeArgument = true +reportNoOverloadImplementation = true +reportOperatorIssue = true +reportOptionalCall = true +reportOptionalContextManager = true +reportOptionalIterable = true +reportOptionalMemberAccess = true +reportOptionalOperand = true +reportOptionalSubscript = true +reportOverlappingOverload = true +reportPossiblyUnboundVariable = true +reportPrivateImportUsage = true +reportPrivateUsage = true +reportPropertyTypeMismatch = true +reportRedeclaration = true +reportReturnType = true +reportSelfClsParameterName = true +reportShadowedImports = true +reportTypeCommentUsage = true +reportTypedDictNotRequiredAccess = true +reportUnboundVariable = true +reportUndefinedVariable = true +reportUnhashable = true +reportUninitializedInstanceVariable = true +reportUnknownArgumentType = true +reportUnknownLambdaType = true +reportUnknownMemberType = true +reportUnknownParameterType = true +reportUnknownVariableType = true +reportUnnecessaryCast = true +reportUnnecessaryComparison = true +reportUnnecessaryContains = true +reportUnnecessaryIsInstance = true +reportUnnecessaryTypeIgnoreComment = true +reportUnsupportedDunderAll = true +reportUntypedBaseClass = true +reportUntypedClassDecorator = true +reportUntypedFunctionDecorator = true +reportUntypedNamedTuple = true +reportUnusedCallResult = true +reportUnusedClass = true +reportUnusedCoroutine = true +reportUnusedExcept = true +reportUnusedExpression = true +reportUnusedFunction = true +reportUnusedImport = true +reportUnusedVariable = true +reportWildcardImportFromLibrary = true + +reportDeprecated = true + +# Can be enabled by generating type stubs for modules via pyright CLI +reportMissingTypeStubs = false + +# Bad rules +# These are sorted alphabetically and should be enabled and moved to compliant rules section when resolved. From fd73176e53e5015889837c30e148ca0e33d947f2 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sun, 22 Jun 2025 14:47:12 -0600 Subject: [PATCH 251/362] Readme: mention Pyright --- readme.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 9f72969..0495029 100644 --- a/readme.md +++ b/readme.md @@ -40,15 +40,17 @@ In addition, this template includes configuration files for the following tools * Press `control+shift+m` after saving a file to search for problems. * Use arrow and tab keys for the autocompletion feature. * Press `control+shift+p` to open the commands palette and search for recommended extensions to install or check if they are installed. +* Pyright (pyproject.toml/tool.pyright sections): a Python static type checker. Sections starting with tool.pyright house configuration options for Pyright. ## Requirements You need the following software to use this code for your NVDA add-on development and packaging: -* a Python distribution (3.11 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.11. +* a Python distribution (3.11 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.11 with 64-bit version planned. * Scons - [Website](https://www.scons.org/) - version 4.8.1 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). * Markdown 3.7 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. +* Optional: additional tools such as linters and type checkers defined in pyproject.toml file. Note, that you may not need these tools in a local build environment, if you are using [Appveyor](https://appveyor.com/) or [GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions), to build and package your add-ons. @@ -148,7 +150,8 @@ Note: you must fill out this dictionary if at least one custom symbol dictionary The template includes configuration files for use with additional tools such as linters. These include: -* Ruff (pyproject.toml): a Python linter written in Rust (0.4.10 or later, can be installed with PIP). +* Ruff: a Python linter written in Rust (0.4.10 or later, can be installed with PIP). +* Pyright: a Python static type checker (1.1.402 or later, can be installed with PIP). Read the documentation for the tools you wish to use when building and developing add-ons. From 72a2c1408b23045e0bdc9634e89796c20bba6d45 Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 17 Jul 2025 10:26:57 +0000 Subject: [PATCH 252/362] buildVars: move down dont_write_bytecode after comment --- sconstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index ac689d2..257d1b4 100644 --- a/sconstruct +++ b/sconstruct @@ -13,9 +13,10 @@ import sys # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. EnsurePythonVersion(3, 10) -sys.dont_write_bytecode = True # Bytecode should not be written for build vars module to keep the repository root folder clean. +sys.dont_write_bytecode = True + import buildVars # NOQA: E402 From 21abd0e9ac0c41074526e9bd4c593ca8e57c0479 Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 17 Jul 2025 10:53:02 +0000 Subject: [PATCH 253/362] SConstruct: add matchesNoPatterns function --- sconstruct | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sconstruct b/sconstruct index 257d1b4..4c1ee79 100644 --- a/sconstruct +++ b/sconstruct @@ -9,6 +9,7 @@ import os import os.path import zipfile import sys +from pathlib import Path # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. @@ -163,6 +164,10 @@ def createAddonHelp(dir): env.Depends(addon, readmeTarget) +def machesNoPatterns(path: Path, patterns: list[str]) -> bool: + return all([not path.match(pattern) for pattern in patterns]) + + def createAddonBundleFromPath(path, dest): """Creates a bundle from a directory that contains an addon manifest file.""" basedir = os.path.abspath(path) From a0244e8b6c67a556ce6da03515d8075b7af003bd Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 17 Jul 2025 11:05:15 +0000 Subject: [PATCH 254/362] SConstruct: The function X is rewritten Replaced os.path with pathlib.Path. buildVars.excludedFiles are now checked with Path.match, which means that patterns are supported, not just specific paths. The issue with the difference between \ and / is now fixed. --- sconstruct | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sconstruct b/sconstruct index 4c1ee79..4590298 100644 --- a/sconstruct +++ b/sconstruct @@ -168,18 +168,18 @@ def machesNoPatterns(path: Path, patterns: list[str]) -> bool: return all([not path.match(pattern) for pattern in patterns]) -def createAddonBundleFromPath(path, dest): +def createAddonBundleFromPath(path: str|Path, dest: str): """Creates a bundle from a directory that contains an addon manifest file.""" - basedir = os.path.abspath(path) + if isinstance(path, str): + path = Path(path) + basedir = path.absolute() with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as z: - # FIXME: the include/exclude feature may or may not be useful. Also python files can be pre-compiled. - for dir, dirnames, filenames in os.walk(basedir): - relativePath = os.path.relpath(dir, basedir) - for filename in filenames: - pathInBundle = os.path.join(relativePath, filename) - absPath = os.path.join(dir, filename) - if pathInBundle not in buildVars.excludedFiles: - z.write(absPath, pathInBundle) + for p in basedir.rglob("*"): + if p.is_dir(): + continue + pathInBundle = p.relative_to(basedir) + if machesNoPatterns(pathInBundle, buildVars.excludedFiles): + z.write(p, pathInBundle) return dest From 935ef8d1b1de4f68088450d9bae8b3095df7138c Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 17 Jul 2025 12:44:25 +0000 Subject: [PATCH 255/362] buildVars: Extend comment before excludedFiles --- buildVars.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildVars.py b/buildVars.py index 785c17c..58844ad 100644 --- a/buildVars.py +++ b/buildVars.py @@ -64,6 +64,8 @@ def _(arg): # Files that will be ignored when building the nvda-addon file # Paths are relative to the addon directory, not to the root directory of your addon sources. +# You can either list every file (using ""/") as a path separator, +# or use glob expressions. excludedFiles = [] # Base language for the NVDA add-on From 99722d694488ebc444e486f0dc34d44c2ac82155 Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 21 Jul 2025 17:22:54 +0000 Subject: [PATCH 256/362] SConstruct: Refactor md2html func Replaced os.path with pathlib.Path to simplify the code and make it easier to understand. The code has been slightly formatted for easier reading. --- sconstruct | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/sconstruct b/sconstruct index 4590298..449644a 100644 --- a/sconstruct +++ b/sconstruct @@ -21,16 +21,21 @@ sys.dont_write_bytecode = True import buildVars # NOQA: E402 -def md2html(source, dest): +def md2html(source: str|Path, dest: str): + if isinstance(source, str): + source = Path(source) + import markdown # Use extensions if defined. mdExtensions = buildVars.markdownExtensions - lang = os.path.basename(os.path.dirname(source)).replace("_", "-") - localeLang = os.path.basename(os.path.dirname(source)) + localeLang = source.parent.name + lang = localeLang.replace("_", "-") try: _ = gettext.translation( - "nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang] + "nvda", + localedir=os.path.join("addon", "locale"), + languages=[localeLang] ).gettext summary = _(buildVars.addon_info["addon_summary"]) except Exception: @@ -42,14 +47,14 @@ def md2html(source, dest): '[[!meta title="': "# ", '"]]': " #", } - with codecs.open(source, "r", "utf-8") as f: + with codecs.open(str(source), "r", "utf-8") as f: mdText = f.read() - for k, v in headerDic.items(): - mdText = mdText.replace(k, v, 1) - htmlText = markdown.markdown(mdText, extensions=mdExtensions) + for k, v in headerDic.items(): + mdText = mdText.replace(k, v, 1) + htmlText = markdown.markdown(mdText, extensions=mdExtensions) # Optimization: build resulting HTML text in one go instead of writing parts separately. docText = "\n".join( - [ + ( "", f'', "", @@ -60,7 +65,7 @@ def md2html(source, dest): "\n", htmlText, "\n", - ] + ) ) with codecs.open(dest, "w", "utf-8") as f: f.write(docText) From b982d4dcf20ee16d684a17816b7392b8a80e3c0a Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 21 Jul 2025 18:34:26 +0000 Subject: [PATCH 257/362] SConstruct: Refactor createAddonHelp func - Add typehints - Replace os.path in pathlib.Path --- sconstruct | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sconstruct b/sconstruct index 449644a..686d726 100644 --- a/sconstruct +++ b/sconstruct @@ -157,15 +157,20 @@ env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) -def createAddonHelp(dir): - docsDir = os.path.join(dir, "doc") - if os.path.isfile("style.css"): - cssPath = os.path.join(docsDir, "style.css") - cssTarget = env.Command(cssPath, "style.css", Copy("$TARGET", "$SOURCE")) +def createAddonHelp(dir: str|Path): + if isinstance(dir, str): + dir = Path(dir) + + docsDir = dir / "doc" + cssFile = Path("style.css") + if cssFile.is_file(): + cssPath = docsDir / cssFile + cssTarget = env.Command(str(cssPath), str(cssFile), Copy("$TARGET", "$SOURCE")) env.Depends(addon, cssTarget) - if os.path.isfile("readme.md"): - readmePath = os.path.join(docsDir, buildVars.baseLanguage, "readme.md") - readmeTarget = env.Command(readmePath, "readme.md", Copy("$TARGET", "$SOURCE")) + readmeFile = Path("readme.md") + if readmeFile.is_file(): + readmePath = docsDir / buildVars.baseLanguage / readmeFile + readmeTarget = env.Command(str(readmePath), str(readmeFile), Copy("$TARGET", "$SOURCE")) env.Depends(addon, readmeTarget) From e8e4a274c0420ce1a2b3814c6dc9612dccc716bb Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 21 Jul 2025 18:45:06 +0000 Subject: [PATCH 258/362] SConstruct: Fix typo in name machesNoPaterns Rename the function to matchesNoPatterns --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 686d726..6c427f2 100644 --- a/sconstruct +++ b/sconstruct @@ -174,7 +174,7 @@ def createAddonHelp(dir: str|Path): env.Depends(addon, readmeTarget) -def machesNoPatterns(path: Path, patterns: list[str]) -> bool: +def matchesNoPatterns(path: Path, patterns: list[str]) -> bool: return all([not path.match(pattern) for pattern in patterns]) @@ -188,7 +188,7 @@ def createAddonBundleFromPath(path: str|Path, dest: str): if p.is_dir(): continue pathInBundle = p.relative_to(basedir) - if machesNoPatterns(pathInBundle, buildVars.excludedFiles): + if matchesNoPatterns(pathInBundle, buildVars.excludedFiles): z.write(p, pathInBundle) return dest From 8ca614698f615d81958065e33fbc91b764043ff3 Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 22 Jul 2025 09:52:55 +0000 Subject: [PATCH 259/362] SConstruct: Refactor validateVersionNumber Add typehints to input args. Use Key in raises messages --- sconstruct | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index 6c427f2..52523c5 100644 --- a/sconstruct +++ b/sconstruct @@ -84,16 +84,16 @@ def mdTool(env): env["BUILDERS"]["markdown"] = mdBuilder -def validateVersionNumber(key, val, env): +def validateVersionNumber(key: str, val: str, _): # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. # Ignore all this if version number is not specified. if val == "0.0.0": return versionNumber = val.split(".") if len(versionNumber) < 3: - raise ValueError("versionNumber must have three parts (major.minor.patch)") + raise ValueError(f"{key} must have three parts (major.minor.patch)") if not all([part.isnumeric() for part in versionNumber]): - raise ValueError("versionNumber (major.minor.patch) must be integers") + raise ValueError(f"{key} (major.minor.patch) must be integers") vars = Variables() From 31a57c3185f3f69c15730ac4f55e73dbcd60582b Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 22 Jul 2025 09:58:55 +0000 Subject: [PATCH 260/362] SConstruct: Refactor if env["dev"] section --- sconstruct | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sconstruct b/sconstruct index 52523c5..292a3e6 100644 --- a/sconstruct +++ b/sconstruct @@ -106,13 +106,12 @@ env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", mdTool]) env.Append(**buildVars.addon_info) if env["dev"]: - import datetime + from datetime import date - buildDate = datetime.datetime.now() - year, month, day = str(buildDate.year), str(buildDate.month), str(buildDate.day) - versionTimestamp = "".join([year, month.zfill(2), day.zfill(2)]) - env["addon_version"] = f"{versionTimestamp}.0.0" - env["versionNumber"] = f"{versionTimestamp}.0.0" + versionTimestamp = date.today().strftime('%Y%m%d') + version = f"{versionTimestamp}.0.0" + env["addon_version"] = version + env["versionNumber"] = version env["channel"] = "dev" elif env["version"] is not None: env["addon_version"] = env["version"] From 4b2d2acda1ee5044cb7ec33db9be350fa663d3b3 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 23 Jul 2025 12:14:57 +0000 Subject: [PATCH 261/362] SConstruct: Refactor matchesNoPatterns The argument `patterns` can be any iterable, not only `list` Use `generator expression` instead of `list comprehension` --- sconstruct | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 292a3e6..3c7b1cf 100644 --- a/sconstruct +++ b/sconstruct @@ -10,6 +10,7 @@ import os.path import zipfile import sys from pathlib import Path +from collections.abc import Iterable # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. @@ -173,8 +174,9 @@ def createAddonHelp(dir: str|Path): env.Depends(addon, readmeTarget) -def matchesNoPatterns(path: Path, patterns: list[str]) -> bool: - return all([not path.match(pattern) for pattern in patterns]) +def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: + """Checks if the path, the first argument, does not match any of the patterns passed as the second argument.""" + return not any((path.match(pattern) for pattern in patterns)) def createAddonBundleFromPath(path: str|Path, dest: str): From 12cc3aff2b8ab39c79675634ea84caa4f8cf4403 Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 24 Jul 2025 12:42:09 +0000 Subject: [PATCH 262/362] SConstruct: Update expandGlobs func - env.Glob has been replaced with Path.glob, as this allows patterns such as `dir/**/*.py` or `**.py` to be used, rather than just `dir/*/*/*.py`. - Also added type hints for arguments and return value. --- sconstruct | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 3c7b1cf..84a74bd 100644 --- a/sconstruct +++ b/sconstruct @@ -256,8 +256,9 @@ def generateTranslatedManifest(source, language, out): f.write(result) -def expandGlobs(files): - return [f for pattern in files for f in env.Glob(pattern)] +def expandGlobs(patterns: Iterable[str]) -> list: + base = Path(".") + return [env.File(f) for pattern in patterns for f in base.glob(pattern.lstrip('/'))] addon = env.NVDAAddon(addonFile, env.Dir("addon")) From 8b1b9541500674e4507c40c96e45c47a4dbb516f Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 08:33:14 +0000 Subject: [PATCH 263/362] SConstruct: Removed unnecessary os.path.join Which passed one argument. --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 84a74bd..174d64c 100644 --- a/sconstruct +++ b/sconstruct @@ -273,7 +273,7 @@ for dir in langDirs: moByLang[dir] = moFile env.Depends(moFile, poFile) translatedManifest = env.NVDATranslatedManifest( - dir.File("manifest.ini"), [moFile, os.path.join("manifest-translated.ini.tpl")] + dir.File("manifest.ini"), [moFile, "manifest-translated.ini.tpl"] ) env.Depends(translatedManifest, ["buildVars.py"]) env.Depends(addon, [translatedManifest, moFile]) @@ -312,7 +312,7 @@ env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path -manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl")) +manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), "manifest.ini.tpl") # Ensure manifest is rebuilt if buildVars is updated. env.Depends(manifest, "buildVars.py") From 5b1ba4b6c8c3e02123cfe36ec81159e063458ed0 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 08:54:38 +0000 Subject: [PATCH 264/362] SConstruct: Migrated to pathlib.Path from os.path - Add addonDir & localeDir constants - Most os.path has been replaced with pathlib where it seems appropriate --- sconstruct | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sconstruct b/sconstruct index 174d64c..c3ee599 100644 --- a/sconstruct +++ b/sconstruct @@ -11,6 +11,7 @@ import zipfile import sys from pathlib import Path from collections.abc import Iterable +from typing import Final # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. @@ -22,6 +23,10 @@ sys.dont_write_bytecode = True import buildVars # NOQA: E402 +addonDir: Final = Path("addon/") +localeDir: Final = addonDir / "locale" + + def md2html(source: str|Path, dest: str): if isinstance(source, str): source = Path(source) @@ -35,7 +40,7 @@ def md2html(source: str|Path, dest: str): try: _ = gettext.translation( "nvda", - localedir=os.path.join("addon", "locale"), + localedir=localeDir, languages=[localeLang] ).gettext summary = _(buildVars.addon_info["addon_summary"]) @@ -142,8 +147,8 @@ def manifestGenerator(target, source, env, for_signature): def translatedManifestGenerator(target, source, env, for_signature): - dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) - lang = os.path.basename(dir) + dir = Path(str(source[0])).absolute().parents[1] + lang = dir.name action = env.Action( lambda target, source, env: generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None, @@ -224,7 +229,7 @@ def generateManifest(source, dest): def generateTranslatedManifest(source, language, out): - _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).gettext + _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext vars = {} for var in ("addon_summary", "addon_description"): vars[var] = _(buildVars.addon_info[var]) @@ -263,7 +268,7 @@ def expandGlobs(patterns: Iterable[str]) -> list: addon = env.NVDAAddon(addonFile, env.Dir("addon")) -langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] +langDirs = [f for f in env.Glob(localeDir/"*")] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated moByLang = {} @@ -285,10 +290,10 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager createAddonHelp("addon") -for mdFile in env.Glob(os.path.join("addon", "doc", "*", "*.md")): +for mdFile in env.Glob(addonDir/"doc/*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. - lang = os.path.basename(os.path.dirname(mdFile.get_abspath())) + lang = Path(mdFile.get_abspath()).parent.name moFile = moByLang.get(lang) htmlFile = env.markdown(mdFile) env.Depends(htmlFile, mdFile) @@ -312,7 +317,7 @@ env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path -manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), "manifest.ini.tpl") +manifest = env.NVDAManifest(addonDir/"manifest.ini", "manifest.ini.tpl") # Ensure manifest is rebuilt if buildVars is updated. env.Depends(manifest, "buildVars.py") From df6abb9a6a18184a6055494521def73c257f0e19 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 09:15:45 +0000 Subject: [PATCH 265/362] SConstruct: Replaced literal "addon" with const addonDir --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index c3ee599..90274bf 100644 --- a/sconstruct +++ b/sconstruct @@ -266,7 +266,7 @@ def expandGlobs(patterns: Iterable[str]) -> list: return [env.File(f) for pattern in patterns for f in base.glob(pattern.lstrip('/'))] -addon = env.NVDAAddon(addonFile, env.Dir("addon")) +addon = env.NVDAAddon(addonFile, env.Dir(addonDir)) langDirs = [f for f in env.Glob(localeDir/"*")] @@ -289,7 +289,7 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager -createAddonHelp("addon") +createAddonHelp(addonDir) for mdFile in env.Glob(addonDir/"doc/*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. From 9b52fc4dfe8fd45cf9036dfcc8fd4cbd84b92523 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 11:11:17 +0000 Subject: [PATCH 266/362] SConstruct: Moved down a definition of addonFile --- sconstruct | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 90274bf..483e4b6 100644 --- a/sconstruct +++ b/sconstruct @@ -127,8 +127,6 @@ if "channel" in env and env["channel"] is not None: buildVars.addon_info["addon_version"] = env["addon_version"] buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] -addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") - def addonGenerator(target, source, env, for_signature): action = env.Action( @@ -266,6 +264,7 @@ def expandGlobs(patterns: Iterable[str]) -> list: return [env.File(f) for pattern in patterns for f in base.glob(pattern.lstrip('/'))] +addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir)) langDirs = [f for f in env.Glob(localeDir/"*")] From 2c49e6c6458d97d252d7b8108ee93316caa7d4d6 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 11:24:13 +0000 Subject: [PATCH 267/362] SConstruct: Rewrote iteration over markdown doc files - Defined docsDir constant - Rewrote iteration over addon/doc/*/*.md files --- sconstruct | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 483e4b6..95955a5 100644 --- a/sconstruct +++ b/sconstruct @@ -25,6 +25,7 @@ import buildVars # NOQA: E402 addonDir: Final = Path("addon/") localeDir: Final = addonDir / "locale" +docsDir: Final = addonDir / "doc" def md2html(source: str|Path, dest: str): @@ -289,10 +290,11 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager createAddonHelp(addonDir) -for mdFile in env.Glob(addonDir/"doc/*/*.md"): +for mdPath in docsDir.glob("*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. - lang = Path(mdFile.get_abspath()).parent.name + lang = mdPath.absolute().parent.name + mdFile = env.File(mdPath) moFile = moByLang.get(lang) htmlFile = env.markdown(mdFile) env.Depends(htmlFile, mdFile) From dea8dbf3ce55099c0d31f0987683c6921c7bc85e Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 11:31:10 +0000 Subject: [PATCH 268/362] SConstruct: Updated createAddonHelp func Now the function accepts the path directly to the documentation directory. --- sconstruct | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sconstruct b/sconstruct index 95955a5..8673c9d 100644 --- a/sconstruct +++ b/sconstruct @@ -161,11 +161,10 @@ env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) -def createAddonHelp(dir: str|Path): - if isinstance(dir, str): - dir = Path(dir) +def createAddonHelp(docsDir: str|Path): + if isinstance(docsDir, str): + docsDir = Path(docsDir) - docsDir = dir / "doc" cssFile = Path("style.css") if cssFile.is_file(): cssPath = docsDir / cssFile @@ -289,7 +288,7 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager -createAddonHelp(addonDir) +createAddonHelp(docsDir) for mdPath in docsDir.glob("*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. From 1a259252710532062516865f43b528d4c5f1b81c Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 11:34:59 +0000 Subject: [PATCH 269/362] SConstruct: Rewrote definition of localeDirs list --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 8673c9d..d0063bb 100644 --- a/sconstruct +++ b/sconstruct @@ -267,7 +267,7 @@ def expandGlobs(patterns: Iterable[str]) -> list: addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir)) -langDirs = [f for f in env.Glob(localeDir/"*")] +langDirs = [env.Dir(d) for d in localeDir.glob("*/")] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated moByLang = {} From bbe7b16c841aae317b31465329d9d7da92da00cd Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 14:17:38 +0000 Subject: [PATCH 270/362] SConstruct: Added explicit imports for linter compatibility --- sconstruct | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sconstruct b/sconstruct index d0063bb..9440172 100644 --- a/sconstruct +++ b/sconstruct @@ -13,6 +13,12 @@ from pathlib import Path from collections.abc import Iterable from typing import Final +# While names imported below are available by default in every SConscript +# Linters aren't aware about them. +# To avoid PyRight `reportUndefinedVariable` errors about them they are imported explicitly. +# When using other Scons functions please add them to the line below. +from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environment + # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. EnsurePythonVersion(3, 10) From dddf7afdfc60591966365c5e9fe0fd89257c3b27 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 14:22:25 +0000 Subject: [PATCH 271/362] SConstruct: Added type hints from SCons.Node.FS - Added hints for global variables langDirs and moByLang. - The return value of the expandGlobs function is typed. --- sconstruct | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index 9440172..2d040eb 100644 --- a/sconstruct +++ b/sconstruct @@ -18,6 +18,7 @@ from typing import Final # To avoid PyRight `reportUndefinedVariable` errors about them they are imported explicitly. # When using other Scons functions please add them to the line below. from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environment +from SCons.Node import FS # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. @@ -265,7 +266,7 @@ def generateTranslatedManifest(source, language, out): f.write(result) -def expandGlobs(patterns: Iterable[str]) -> list: +def expandGlobs(patterns: Iterable[str]) -> list[FS.File]: base = Path(".") return [env.File(f) for pattern in patterns for f in base.glob(pattern.lstrip('/'))] @@ -273,10 +274,10 @@ def expandGlobs(patterns: Iterable[str]) -> list: addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir)) -langDirs = [env.Dir(d) for d in localeDir.glob("*/")] +langDirs: list[FS.Dir] = [env.Dir(d) for d in localeDir.glob("*/")] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated -moByLang = {} +moByLang: dict[FS.Dir, FS.File] = {} for dir in langDirs: poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) moFile = env.gettextMoFile(poFile) From 0151f4f29340ceefbb02f208bba6c20641f99b1f Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 14:35:39 +0000 Subject: [PATCH 272/362] buildVars: Added type hints for _ function --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 58844ad..294f1fc 100644 --- a/buildVars.py +++ b/buildVars.py @@ -9,7 +9,7 @@ # Gettext recognizes only strings given as parameters to the `_` function. # To avoid initializing translations in this module we simply roll our own "fake" `_` function # which returns whatever is given to it as an argument. -def _(arg): +def _(arg: str) -> str: return arg From 917d540fe8f09a4052fab5724361cb7cacbe7b75 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 14:55:07 +0000 Subject: [PATCH 273/362] buildVars: Added type hints to variables Vars: - pythonSources - i18nSources - excludedFiles - baseLanguage - markdownExtensions --- buildVars.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/buildVars.py b/buildVars.py index 294f1fc..2d90f5f 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,5 +1,3 @@ -# -*- coding: UTF-8 -*- - # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. @@ -57,29 +55,29 @@ def _(arg: str) -> str: # pythonSources = ["addon/globalPlugins/*.py"] # For more information on SCons Glob expressions please take a look at: # https://scons.org/doc/production/HTML/scons-user/apd.html -pythonSources = [] +pythonSources: list[str] = [] # Files that contain strings for translation. Usually your python sources -i18nSources = pythonSources + ["buildVars.py"] +i18nSources: list[str] = pythonSources + ["buildVars.py"] # Files that will be ignored when building the nvda-addon file # Paths are relative to the addon directory, not to the root directory of your addon sources. # You can either list every file (using ""/") as a path separator, # or use glob expressions. -excludedFiles = [] +excludedFiles: list[str] = [] # Base language for the NVDA add-on # If your add-on is written in a language other than english, modify this variable. # For example, set baseLanguage to "es" if your add-on is primarily written in spanish. # You must also edit .gitignore file to specify base language files to be ignored. -baseLanguage = "en" +baseLanguage: str = "en" # Markdown extensions for add-on documentation # Most add-ons do not require additional Markdown extensions. # If you need to add support for markup such as tables, fill out the below list. # Extensions string must be of the form "markdown.extensions.extensionName" # e.g. "markdown.extensions.tables" to add tables. -markdownExtensions = [] +markdownExtensions: list[str] = [] # Custom braille translation tables # If your add-on includes custom braille tables (most will not), fill out this dictionary. From 30ae096e6df51b997548f5ece8869f12900c69e4 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 15:09:09 +0000 Subject: [PATCH 274/362] buildVars: Added AddonInfo typed dict --- buildVars.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index 2d90f5f..3db2cc2 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,6 +1,7 @@ # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. +from typing import TypedDict # Since some strings in `addon_info` are translatable, # we need to include them in the .po files. @@ -11,8 +12,24 @@ def _(arg: str) -> str: return arg +# A typed dictionary for storing meta information about add-on. +class AddonInfo(TypedDict): + addon_name: str + addon_summary: str + addon_description: str + addon_version: str + addon_author: str + addon_url: str|None + addon_sourceURL: str|None + addon_docFileName: str + addon_minimumNVDAVersion: str|None + addon_lastTestedNVDAVersion: str|None + addon_updateChannel: str|None + addon_license: str|None + addon_licenseURL: str|None + # Add-on information variables -addon_info = { +addon_info: AddonInfo = { # add-on Name/identifier, internal for NVDA "addon_name": "addonTemplate", # Add-on summary/title, usually the user visible name of the add-on From 2577e43f0cae39cfa0da3e174efdb92f2a4db12c Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 27 Jul 2025 16:04:38 +0000 Subject: [PATCH 275/362] SConstruct: Fixed build in Linux environment --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 2d040eb..6bda520 100644 --- a/sconstruct +++ b/sconstruct @@ -324,7 +324,7 @@ env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path -manifest = env.NVDAManifest(addonDir/"manifest.ini", "manifest.ini.tpl") +manifest = env.NVDAManifest(env.File(addonDir/"manifest.ini"), "manifest.ini.tpl") # Ensure manifest is rebuilt if buildVars is updated. env.Depends(manifest, "buildVars.py") From 0f434d43369d74f60496c77c7ad3e0057265e2cd Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 28 Jul 2025 09:10:42 +0000 Subject: [PATCH 276/362] SConstruct: Extend commit bbe7b16 Added Builder & Copy to list of imports from SCons.Script --- sconstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 6bda520..80be12a 100644 --- a/sconstruct +++ b/sconstruct @@ -17,7 +17,7 @@ from typing import Final # Linters aren't aware about them. # To avoid PyRight `reportUndefinedVariable` errors about them they are imported explicitly. # When using other Scons functions please add them to the line below. -from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environment +from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environment, Builder, Copy from SCons.Node import FS # Add-on localization exchange facility and the template requires Python 3.10. From 97ed6d16978d08a2857807de7a33decb2e0ce076 Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 28 Jul 2025 10:17:53 +0000 Subject: [PATCH 277/362] SConstruct: Improved type hints Input arguments & return value type hints for functions: - addonGenerator - manifestGenerator - translatedManifestGenerator - generateManifest - generateTranslatedManifest --- sconstruct | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sconstruct b/sconstruct index 80be12a..e1de63d 100644 --- a/sconstruct +++ b/sconstruct @@ -18,7 +18,10 @@ from typing import Final # To avoid PyRight `reportUndefinedVariable` errors about them they are imported explicitly. # When using other Scons functions please add them to the line below. from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environment, Builder, Copy + +# Imports for type hints from SCons.Node import FS +from SCons.Action import CommandAction # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. @@ -85,7 +88,7 @@ def md2html(source: str|Path, dest: str): f.write(docText) -def mdTool(env): +def mdTool(env: Environment): mdAction = env.Action( lambda target, source, env: md2html(source[0].path, target[0].path), lambda target, source, env: f"Generating {target[0]}", @@ -136,7 +139,7 @@ buildVars.addon_info["addon_version"] = env["addon_version"] buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] -def addonGenerator(target, source, env, for_signature): +def addonGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: action = env.Action( lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, lambda target, source, env: f"Generating Addon {target[0]}", @@ -144,7 +147,7 @@ def addonGenerator(target, source, env, for_signature): return action -def manifestGenerator(target, source, env, for_signature): +def manifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: action = env.Action( lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, lambda target, source, env: f"Generating manifest {target[0]}", @@ -152,7 +155,7 @@ def manifestGenerator(target, source, env, for_signature): return action -def translatedManifestGenerator(target, source, env, for_signature): +def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: dir = Path(str(source[0])).absolute().parents[1] lang = dir.name action = env.Action( @@ -204,7 +207,7 @@ def createAddonBundleFromPath(path: str|Path, dest: str): return dest -def generateManifest(source, dest): +def generateManifest(source: str, dest: str): # Prepare the root manifest section addon_info = buildVars.addon_info with codecs.open(source, "r", "utf-8") as f: @@ -233,7 +236,7 @@ def generateManifest(source, dest): f.write(manifest) -def generateTranslatedManifest(source, language, out): +def generateTranslatedManifest(source: str, language: str, out: str): _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext vars = {} for var in ("addon_summary", "addon_description"): From 28459b8792c702e14e6d87f586e1b1d973ace719 Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 28 Jul 2025 10:33:25 +0000 Subject: [PATCH 278/362] SConstruct: Updated expandGlobs function Replaced FS.File to FS.Entry Added rootdir not required argument Renamded f to e --- sconstruct | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index e1de63d..ae77839 100644 --- a/sconstruct +++ b/sconstruct @@ -269,9 +269,8 @@ def generateTranslatedManifest(source: str, language: str, out: str): f.write(result) -def expandGlobs(patterns: Iterable[str]) -> list[FS.File]: - base = Path(".") - return [env.File(f) for pattern in patterns for f in base.glob(pattern.lstrip('/'))] +def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.Entry]: + return [env.Entry(e) for pattern in patterns for e in rootdir.glob(pattern.lstrip('/'))] addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") From e9efd87ed467a7676282e85713f74ec862b0540b Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 28 Jul 2025 12:52:50 +0000 Subject: [PATCH 279/362] SConstruct: Updated mdTool All dependencies are now accepted as arguments, instead of global variables (localeDir) or modules (buildVars). --- sconstruct | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/sconstruct b/sconstruct index ae77839..0bdd047 100644 --- a/sconstruct +++ b/sconstruct @@ -38,28 +38,34 @@ localeDir: Final = addonDir / "locale" docsDir: Final = addonDir / "doc" -def md2html(source: str|Path, dest: str): +def md2html( + source: str|Path, + dest: str, + *, + localeDir: Path, + loacleFileName: str, + mdExtensions: list[str], + addonSummary: str, + addonVersion: str + ): if isinstance(source, str): source = Path(source) import markdown # Use extensions if defined. - mdExtensions = buildVars.markdownExtensions localeLang = source.parent.name lang = localeLang.replace("_", "-") try: _ = gettext.translation( - "nvda", + loacleFileName, localedir=localeDir, languages=[localeLang] ).gettext - summary = _(buildVars.addon_info["addon_summary"]) + summary = _(addonSummary) except Exception: - summary = buildVars.addon_info["addon_summary"] - title = "{addonSummary} {addonVersion}".format( - addonSummary=summary, addonVersion=buildVars.addon_info["addon_version"] - ) + summary = addonSummary + title = f"{summary} {addonVersion}" headerDic = { '[[!meta title="': "# ", '"]]': " #", @@ -89,8 +95,20 @@ def md2html(source: str|Path, dest: str): def mdTool(env: Environment): + env.SetDefault(localeDir = Path("locale/")) + env.SetDefault(localeFileName = "messages") + env.SetDefault(mdExtensions = {}) + mdAction = env.Action( - lambda target, source, env: md2html(source[0].path, target[0].path), + lambda target, source, env: md2html( + source[0].path, + target[0].path, + localeDir=env["localeDir"], + loacleFileName=env["localeFileName"], + mdExtensions=env["mdExtensions"], + addonSummary=env["addon_summary"], + addonVersion=env["addon_version"] + ), lambda target, source, env: f"Generating {target[0]}", ) mdBuilder = env.Builder( @@ -304,7 +322,7 @@ for mdPath in docsDir.glob("*/*.md"): lang = mdPath.absolute().parent.name mdFile = env.File(mdPath) moFile = moByLang.get(lang) - htmlFile = env.markdown(mdFile) + htmlFile = env.markdown(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) env.Depends(htmlFile, mdFile) if moFile: env.Depends(htmlFile, moFile) From ec449448d94bbe3849fdf1258b1cc805e75c4b58 Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 28 Jul 2025 14:35:51 +0000 Subject: [PATCH 280/362] SConstruct, mdTool: Moved mdTool & md2html to site_tools --- sconstruct | 83 +---------------- site_scons/site_tools/mdTool/__init__.py | 108 +++++++++++++++++++++++ 2 files changed, 109 insertions(+), 82 deletions(-) create mode 100644 site_scons/site_tools/mdTool/__init__.py diff --git a/sconstruct b/sconstruct index 0bdd047..735936e 100644 --- a/sconstruct +++ b/sconstruct @@ -38,87 +38,6 @@ localeDir: Final = addonDir / "locale" docsDir: Final = addonDir / "doc" -def md2html( - source: str|Path, - dest: str, - *, - localeDir: Path, - loacleFileName: str, - mdExtensions: list[str], - addonSummary: str, - addonVersion: str - ): - if isinstance(source, str): - source = Path(source) - - import markdown - - # Use extensions if defined. - localeLang = source.parent.name - lang = localeLang.replace("_", "-") - try: - _ = gettext.translation( - loacleFileName, - localedir=localeDir, - languages=[localeLang] - ).gettext - summary = _(addonSummary) - except Exception: - summary = addonSummary - title = f"{summary} {addonVersion}" - headerDic = { - '[[!meta title="': "# ", - '"]]': " #", - } - with codecs.open(str(source), "r", "utf-8") as f: - mdText = f.read() - for k, v in headerDic.items(): - mdText = mdText.replace(k, v, 1) - htmlText = markdown.markdown(mdText, extensions=mdExtensions) - # Optimization: build resulting HTML text in one go instead of writing parts separately. - docText = "\n".join( - ( - "", - f'', - "", - '', - '', - '', - f"{title}", - "\n", - htmlText, - "\n", - ) - ) - with codecs.open(dest, "w", "utf-8") as f: - f.write(docText) - - -def mdTool(env: Environment): - env.SetDefault(localeDir = Path("locale/")) - env.SetDefault(localeFileName = "messages") - env.SetDefault(mdExtensions = {}) - - mdAction = env.Action( - lambda target, source, env: md2html( - source[0].path, - target[0].path, - localeDir=env["localeDir"], - loacleFileName=env["localeFileName"], - mdExtensions=env["mdExtensions"], - addonSummary=env["addon_summary"], - addonVersion=env["addon_version"] - ), - lambda target, source, env: f"Generating {target[0]}", - ) - mdBuilder = env.Builder( - action=mdAction, - suffix=".html", - src_suffix=".md", - ) - env["BUILDERS"]["markdown"] = mdBuilder - - def validateVersionNumber(key: str, val: str, _): # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. # Ignore all this if version number is not specified. @@ -137,7 +56,7 @@ vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0 vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) -env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", mdTool]) +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool"]) env.Append(**buildVars.addon_info) if env["dev"]: diff --git a/site_scons/site_tools/mdTool/__init__.py b/site_scons/site_tools/mdTool/__init__.py new file mode 100644 index 0000000..8128189 --- /dev/null +++ b/site_scons/site_tools/mdTool/__init__.py @@ -0,0 +1,108 @@ +""" +This tool allows you to generate HTML files from Markdown. + +Adds the following Builder to the constructed environment: + +- markdown: Build HTML from Markdown + +The following variables are required in the environment: + +- localeDir +- localeFileName +- mdExtensions +- addon_summary +- addon_version + + +""" + +import gettext +import codecs +from pathlib import Path + +import markdown +from SCons.Script import Environment + + + +def md2html( + source: str|Path, + dest: str, + *, + localeDir: Path, + loacleFileName: str, + mdExtensions: list[str], + addonSummary: str, + addonVersion: str + ): + if isinstance(source, str): + source = Path(source) + + # Use extensions if defined. + localeLang = source.parent.name + lang = localeLang.replace("_", "-") + try: + _ = gettext.translation( + loacleFileName, + localedir=localeDir, + languages=[localeLang] + ).gettext + summary = _(addonSummary) + except Exception: + summary = addonSummary + title = f"{summary} {addonVersion}" + headerDic = { + '[[!meta title="': "# ", + '"]]': " #", + } + with codecs.open(str(source), "r", "utf-8") as f: + mdText = f.read() + for k, v in headerDic.items(): + mdText = mdText.replace(k, v, 1) + htmlText = markdown.markdown(mdText, extensions=mdExtensions) + # Optimization: build resulting HTML text in one go instead of writing parts separately. + docText = "\n".join( + ( + "", + f'', + "", + '', + '', + '', + f"{title}", + "\n", + htmlText, + "\n", + ) + ) + with codecs.open(dest, "w", "utf-8") as f: + f.write(docText) + + +def generate(env: Environment): + env.SetDefault(localeDir = Path("locale/")) + env.SetDefault(localeFileName = "messages") + env.SetDefault(mdExtensions = {}) + + mdAction = env.Action( + lambda target, source, env: md2html( + source[0].path, + target[0].path, + localeDir=env["localeDir"], + loacleFileName=env["localeFileName"], + mdExtensions=env["mdExtensions"], + addonSummary=env["addon_summary"], + addonVersion=env["addon_version"] + ), + lambda target, source, env: f"Generating {target[0]}", + ) + mdBuilder = env.Builder( + action=mdAction, + suffix=".html", + src_suffix=".md", + ) + env["BUILDERS"]["markdown"] = mdBuilder + + +def exists(): + return True From 53363bf985efcabf4cec23c44a9484b18814371b Mon Sep 17 00:00:00 2001 From: balaraz Date: Mon, 28 Jul 2025 14:48:35 +0000 Subject: [PATCH 281/362] mdTool: Fixed mdAction lambda funcs Fixed the return value of the first lambda function so that it is negative and the second function is called, which returns the string that is output to the terminal. --- site_scons/site_tools/mdTool/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site_scons/site_tools/mdTool/__init__.py b/site_scons/site_tools/mdTool/__init__.py index 8128189..05fac06 100644 --- a/site_scons/site_tools/mdTool/__init__.py +++ b/site_scons/site_tools/mdTool/__init__.py @@ -93,7 +93,7 @@ def generate(env: Environment): mdExtensions=env["mdExtensions"], addonSummary=env["addon_summary"], addonVersion=env["addon_version"] - ), + ) and None, lambda target, source, env: f"Generating {target[0]}", ) mdBuilder = env.Builder( From a34ce1faad0f4510a3f78b83a4492ea176279498 Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 06:29:19 +0000 Subject: [PATCH 282/362] SConstruct: Returned env.Glob instead of Path.glob When iterating over localization directories and documentation files, env.Glob is now used again to fix the generation of the base language HTML file --- sconstruct | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index 735936e..d7d9bff 100644 --- a/sconstruct +++ b/sconstruct @@ -213,7 +213,7 @@ def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.E addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir)) -langDirs: list[FS.Dir] = [env.Dir(d) for d in localeDir.glob("*/")] +langDirs: list[FS.Dir] = [d for d in env.Glob(localeDir/"*/")] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated moByLang: dict[FS.Dir, FS.File] = {} @@ -235,11 +235,10 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager createAddonHelp(docsDir) -for mdPath in docsDir.glob("*/*.md"): +for mdFile in env.Glob(docsDir/"*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. - lang = mdPath.absolute().parent.name - mdFile = env.File(mdPath) + lang = Path(str(mdFile)).absolute().parent.name moFile = moByLang.get(lang) htmlFile = env.markdown(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) env.Depends(htmlFile, mdFile) From 20ff630cda350d2f86e814c74f98316a793c301b Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 09:45:11 +0000 Subject: [PATCH 283/362] buildVars, SConstruct: Added type hints to non typed vars buildVars: - brailleTables - symbolDictionaries SConstruct: - gettextvars - generateTranslatedManifest:vars diff --git a/buildVars.py b/buildVars.py index 3db2cc2..4eaaef1 100644 --- a/buildVars.py +++ b/buildVars.py @@ -104,7 +104,7 @@ markdownExtensions: list[str] = [] # contracted (contracted (True) or uncontracted (False) braille code), # output (shown in output table list), # input (shown in input table list). -brailleTables = {} +brailleTables: dict[str, dict[str, str]] = {} # Custom speech symbol dictionaries # Symbol dictionary files reside in the locale folder, e.g. `locale\en`, and are named `symbols-.dic`. @@ -113,4 +113,4 @@ brailleTables = {} # with keys inside recording the following attributes: # displayName (name of the speech dictionary shown to users and translatable), # mandatory (True when always enabled, False when not. -symbolDictionaries = {} +symbolDictionaries: dict[str, dict[str, str]] = {} diff --git a/buildVars.py b/buildVars.py index 3db2cc2..4eaaef1 100644 --- a/buildVars.py +++ b/buildVars.py @@ -104,7 +104,7 @@ markdownExtensions: list[str] = [] # contracted (contracted (True) or uncontracted (False) braille code), # output (shown in output table list), # input (shown in input table list). -brailleTables = {} +brailleTables: dict[str, dict[str, str]] = {} # Custom speech symbol dictionaries # Symbol dictionary files reside in the locale folder, e.g. `locale\en`, and are named `symbols-.dic`. @@ -113,4 +113,4 @@ brailleTables = {} # with keys inside recording the following attributes: # displayName (name of the speech dictionary shown to users and translatable), # mandatory (True when always enabled, False when not. -symbolDictionaries = {} +symbolDictionaries: dict[str, dict[str, str]] = {} --- buildVars.py | 4 ++-- sconstruct | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildVars.py b/buildVars.py index 3db2cc2..4eaaef1 100644 --- a/buildVars.py +++ b/buildVars.py @@ -104,7 +104,7 @@ class AddonInfo(TypedDict): # contracted (contracted (True) or uncontracted (False) braille code), # output (shown in output table list), # input (shown in input table list). -brailleTables = {} +brailleTables: dict[str, dict[str, str]] = {} # Custom speech symbol dictionaries # Symbol dictionary files reside in the locale folder, e.g. `locale\en`, and are named `symbols-.dic`. @@ -113,4 +113,4 @@ class AddonInfo(TypedDict): # with keys inside recording the following attributes: # displayName (name of the speech dictionary shown to users and translatable), # mandatory (True when always enabled, False when not. -symbolDictionaries = {} +symbolDictionaries: dict[str, dict[str, str]] = {} diff --git a/sconstruct b/sconstruct index d7d9bff..bd4d961 100644 --- a/sconstruct +++ b/sconstruct @@ -175,7 +175,7 @@ def generateManifest(source: str, dest: str): def generateTranslatedManifest(source: str, language: str, out: str): _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext - vars = {} + vars: dict[str, str] = {} for var in ("addon_summary", "addon_description"): vars[var] = _(buildVars.addon_info[var]) with codecs.open(source, "r", "utf-8") as f: @@ -248,7 +248,7 @@ for mdFile in env.Glob(docsDir/"*/*.md"): # Pot target i18nFiles = expandGlobs(buildVars.i18nSources) -gettextvars = { +gettextvars: dict[str, str] = { "gettext_package_bugs_address": "nvda-translations@groups.io", "gettext_package_name": buildVars.addon_info["addon_name"], "gettext_package_version": buildVars.addon_info["addon_version"], From 0071a85ad54d2b2f97ce202735f1c8123bdc0b27 Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 14:02:53 +0000 Subject: [PATCH 284/362] SConstruct:Refactored if getattr calls Replaced getattr to hasattr in: - generateManifest - generateTranslatedManifest --- sconstruct | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index bd4d961..051925f 100644 --- a/sconstruct +++ b/sconstruct @@ -152,7 +152,7 @@ def generateManifest(source: str, dest: str): manifest = manifest_template.format(**addon_info) # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if getattr(buildVars, "brailleTables", {}): + if hasattr(buildVars, "brailleTables"): manifest_brailleTables = ["\n[brailleTables]"] for table in buildVars.brailleTables.keys(): manifest_brailleTables.append(f"[[{table}]]") @@ -161,7 +161,7 @@ def generateManifest(source: str, dest: str): manifest += "\n".join(manifest_brailleTables) + "\n" # Custom speech symbol dictionaries - if getattr(buildVars, "symbolDictionaries", {}): + if hasattr(buildVars, "symbolDictionaries"): manifest_symbolDictionaries = ["\n[symbolDictionaries]"] for dictionary in buildVars.symbolDictionaries.keys(): manifest_symbolDictionaries.append(f"[[{dictionary}]]") @@ -183,7 +183,7 @@ def generateTranslatedManifest(source: str, language: str, out: str): result = manifest_template.format(**vars) # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if getattr(buildVars, "brailleTables", {}): + if hasattr(buildVars, "brailleTables"): result_brailleTables = ["\n[brailleTables]"] for table in buildVars.brailleTables.keys(): result_brailleTables.append(f"[[{table}]]") @@ -192,7 +192,7 @@ def generateTranslatedManifest(source: str, language: str, out: str): result += "\n".join(result_brailleTables) + "\n" # Custom speech symbol dictionaries - if getattr(buildVars, "symbolDictionaries", {}): + if hasattr(buildVars, "symbolDictionaries"): result_symbolDictionaries = ["\n[symbolDictionaries]"] for dictionary in buildVars.symbolDictionaries.keys(): result_symbolDictionaries.append(f"[[{dictionary}]]") From 76b7120bcc1df53462ddf9bcbf76a1264e0b1cc5 Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 14:20:26 +0000 Subject: [PATCH 285/362] SConstruct: Added format_nested_section func --- sconstruct | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sconstruct b/sconstruct index 051925f..078d792 100644 --- a/sconstruct +++ b/sconstruct @@ -11,7 +11,7 @@ import zipfile import sys from pathlib import Path from collections.abc import Iterable -from typing import Final +from typing import Final, Mapping # While names imported below are available by default in every SConscript # Linters aren't aware about them. @@ -144,6 +144,18 @@ def createAddonBundleFromPath(path: str|Path, dest: str): return dest +def format_nested_section( + section_name: str, + data: Mapping[str, Mapping[str, str]] +) -> str: + lines = [f"\n[{section_name}]"] + for item_name, inner_dict in data.items(): + lines.append(f"[[{item_name}]]") + for key, val in inner_dict.items(): + lines.append(f"{key} = {val}") + return "\n".join(lines) + "\n" + + def generateManifest(source: str, dest: str): # Prepare the root manifest section addon_info = buildVars.addon_info From 7bbf1af7f14f112f6f72604e66db60503977808c Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 14:39:04 +0000 Subject: [PATCH 286/362] SConstruct: Update generateManifest Use format_nested_section in both `if hasattr` blocks --- sconstruct | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/sconstruct b/sconstruct index 078d792..6a366c5 100644 --- a/sconstruct +++ b/sconstruct @@ -165,21 +165,11 @@ def generateManifest(source: str, dest: str): # Add additional manifest sections such as custom braile tables # Custom braille translation tables if hasattr(buildVars, "brailleTables"): - manifest_brailleTables = ["\n[brailleTables]"] - for table in buildVars.brailleTables.keys(): - manifest_brailleTables.append(f"[[{table}]]") - for key, val in buildVars.brailleTables[table].items(): - manifest_brailleTables.append(f"{key} = {val}") - manifest += "\n".join(manifest_brailleTables) + "\n" + manifest += format_nested_section("brailleTables", buildVars.brailleTables) # Custom speech symbol dictionaries if hasattr(buildVars, "symbolDictionaries"): - manifest_symbolDictionaries = ["\n[symbolDictionaries]"] - for dictionary in buildVars.symbolDictionaries.keys(): - manifest_symbolDictionaries.append(f"[[{dictionary}]]") - for key, val in buildVars.symbolDictionaries[dictionary].items(): - manifest_symbolDictionaries.append(f"{key} = {val}") - manifest += "\n".join(manifest_symbolDictionaries) + "\n" + manifest += format_nested_section("symbolDictionaries", buildVars.symbolDictionaries) with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) From 21b273316b5e7bf77a47296926560eaaeedec5d4 Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 17:13:38 +0000 Subject: [PATCH 287/362] SConstruct: Refactored generateTranslatedManifest - Renamed input argument `out` to `dest` - Renamed local var `result` to `manifest` - Created inner _format_section_only_with_displayName function - `if hasattr` blocks has been changed to use the above-mentioned function diff --git a/sconstruct b/sconstruct index 6a366c5..d57bd5b 100644 --- a/sconstruct +++ b/sconstruct @@ -175,37 +175,34 @@ def generateManifest(source: str, dest: str): f.write(manifest) -def generateTranslatedManifest(source: str, language: str, out: str): +def generateTranslatedManifest(source: str, language: str, dest: str): _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext vars: dict[str, str] = {} for var in ("addon_summary", "addon_description"): vars[var] = _(buildVars.addon_info[var]) with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() - result = manifest_template.format(**vars) + manifest = manifest_template.format(**vars) + + def _format_section_only_with_displayName(section_name: str, data: Mapping[str, Mapping[str, str]]) -> str: + lines = [f"\n[{section_name}]"] + for item, inner_dict in data.items(): + lines.append(f"[[{item}]]") + # Fetch display name only. + lines.append(f"displayName = {_(inner_dict['displayName'])}") + return "\n".join(lines) + "\n" + # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if hasattr(buildVars, "brailleTables"): - result_brailleTables = ["\n[brailleTables]"] - for table in buildVars.brailleTables.keys(): - result_brailleTables.append(f"[[{table}]]") - # Fetch display name only. - result_brailleTables.append(f"displayName = {_(buildVars.brailleTables[table]['displayName'])}") - result += "\n".join(result_brailleTables) + "\n" + if tables := getattr(buildVars, "brailleTables", None): + manifest += _format_section_only_with_displayName("brailleTables", tables) # Custom speech symbol dictionaries - if hasattr(buildVars, "symbolDictionaries"): - result_symbolDictionaries = ["\n[symbolDictionaries]"] - for dictionary in buildVars.symbolDictionaries.keys(): - result_symbolDictionaries.append(f"[[{dictionary}]]") - # Fetch display name only. - result_symbolDictionaries.append( - f"displayName = {_(buildVars.symbolDictionaries[dictionary]['displayName'])}" - ) - result += "\n".join(result_symbolDictionaries) + "\n" + if dicts := getattr(buildVars, "symbolDictionaries", None): + manifest += _format_section_only_with_displayName("symbolDictionaries", dicts) - with codecs.open(out, "w", "utf-8") as f: - f.write(result) + with codecs.open(dest, "w", "utf-8") as f: + f.write(manifest) def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.Entry]: --- sconstruct | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/sconstruct b/sconstruct index 6a366c5..d57bd5b 100644 --- a/sconstruct +++ b/sconstruct @@ -175,37 +175,34 @@ def generateManifest(source: str, dest: str): f.write(manifest) -def generateTranslatedManifest(source: str, language: str, out: str): +def generateTranslatedManifest(source: str, language: str, dest: str): _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext vars: dict[str, str] = {} for var in ("addon_summary", "addon_description"): vars[var] = _(buildVars.addon_info[var]) with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() - result = manifest_template.format(**vars) + manifest = manifest_template.format(**vars) + + def _format_section_only_with_displayName(section_name: str, data: Mapping[str, Mapping[str, str]]) -> str: + lines = [f"\n[{section_name}]"] + for item, inner_dict in data.items(): + lines.append(f"[[{item}]]") + # Fetch display name only. + lines.append(f"displayName = {_(inner_dict['displayName'])}") + return "\n".join(lines) + "\n" + # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if hasattr(buildVars, "brailleTables"): - result_brailleTables = ["\n[brailleTables]"] - for table in buildVars.brailleTables.keys(): - result_brailleTables.append(f"[[{table}]]") - # Fetch display name only. - result_brailleTables.append(f"displayName = {_(buildVars.brailleTables[table]['displayName'])}") - result += "\n".join(result_brailleTables) + "\n" + if tables := getattr(buildVars, "brailleTables", None): + manifest += _format_section_only_with_displayName("brailleTables", tables) # Custom speech symbol dictionaries - if hasattr(buildVars, "symbolDictionaries"): - result_symbolDictionaries = ["\n[symbolDictionaries]"] - for dictionary in buildVars.symbolDictionaries.keys(): - result_symbolDictionaries.append(f"[[{dictionary}]]") - # Fetch display name only. - result_symbolDictionaries.append( - f"displayName = {_(buildVars.symbolDictionaries[dictionary]['displayName'])}" - ) - result += "\n".join(result_symbolDictionaries) + "\n" + if dicts := getattr(buildVars, "symbolDictionaries", None): + manifest += _format_section_only_with_displayName("symbolDictionaries", dicts) - with codecs.open(out, "w", "utf-8") as f: - f.write(result) + with codecs.open(dest, "w", "utf-8") as f: + f.write(manifest) def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.Entry]: From a25f882440d3b9b2cf0887e54efddee9d6135a40 Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 17:30:48 +0000 Subject: [PATCH 288/362] mdTool, SConstruct: Renamed markdown builder to md2html diff --git a/sconstruct b/sconstruct index d57bd5b..29e584c 100644 --- a/sconstruct +++ b/sconstruct @@ -239,7 +239,7 @@ for mdFile in env.Glob(docsDir/"*/*.md"): # Thus, we find the moFile for this language and depend on it if it exists. lang = Path(str(mdFile)).absolute().parent.name moFile = moByLang.get(lang) - htmlFile = env.markdown(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) + htmlFile = env.md2html(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) env.Depends(htmlFile, mdFile) if moFile: env.Depends(htmlFile, moFile) diff --git a/site_scons/site_tools/mdTool/__init__.py b/site_scons/site_tools/mdTool/__init__.py index 05fac06..5547237 100644 --- a/site_scons/site_tools/mdTool/__init__.py +++ b/site_scons/site_tools/mdTool/__init__.py @@ -3,7 +3,7 @@ This tool allows you to generate HTML files from Markdown. Adds the following Builder to the constructed environment: -- markdown: Build HTML from Markdown +- md2html: Build HTML from Markdown The following variables are required in the environment: @@ -101,7 +101,7 @@ def generate(env: Environment): suffix=".html", src_suffix=".md", ) - env["BUILDERS"]["markdown"] = mdBuilder + env["BUILDERS"]["md2html"] = mdBuilder def exists(): --- sconstruct | 2 +- site_scons/site_tools/mdTool/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index d57bd5b..29e584c 100644 --- a/sconstruct +++ b/sconstruct @@ -239,7 +239,7 @@ for mdFile in env.Glob(docsDir/"*/*.md"): # Thus, we find the moFile for this language and depend on it if it exists. lang = Path(str(mdFile)).absolute().parent.name moFile = moByLang.get(lang) - htmlFile = env.markdown(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) + htmlFile = env.md2html(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) env.Depends(htmlFile, mdFile) if moFile: env.Depends(htmlFile, moFile) diff --git a/site_scons/site_tools/mdTool/__init__.py b/site_scons/site_tools/mdTool/__init__.py index 05fac06..5547237 100644 --- a/site_scons/site_tools/mdTool/__init__.py +++ b/site_scons/site_tools/mdTool/__init__.py @@ -3,7 +3,7 @@ Adds the following Builder to the constructed environment: -- markdown: Build HTML from Markdown +- md2html: Build HTML from Markdown The following variables are required in the environment: @@ -101,7 +101,7 @@ def generate(env: Environment): suffix=".html", src_suffix=".md", ) - env["BUILDERS"]["markdown"] = mdBuilder + env["BUILDERS"]["md2html"] = mdBuilder def exists(): From 9526341f5fd10437feadc96f0cd8897724a2bf23 Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 29 Jul 2025 17:45:26 +0000 Subject: [PATCH 289/362] SConstruct: Removed createAddonHelp func The script has been simplified because the function used the global variable addon, which is declared after the function itself. This made it difficult to understand, and it was called only once. diff --git a/sconstruct b/sconstruct index 29e584c..bc6ff74 100644 --- a/sconstruct +++ b/sconstruct @@ -108,22 +108,6 @@ env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) -def createAddonHelp(docsDir: str|Path): - if isinstance(docsDir, str): - docsDir = Path(docsDir) - - cssFile = Path("style.css") - if cssFile.is_file(): - cssPath = docsDir / cssFile - cssTarget = env.Command(str(cssPath), str(cssFile), Copy("$TARGET", "$SOURCE")) - env.Depends(addon, cssTarget) - readmeFile = Path("readme.md") - if readmeFile.is_file(): - readmePath = docsDir / buildVars.baseLanguage / readmeFile - readmeTarget = env.Command(str(readmePath), str(readmeFile), Copy("$TARGET", "$SOURCE")) - env.Depends(addon, readmeTarget) - - def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: """Checks if the path, the first argument, does not match any of the patterns passed as the second argument.""" return not any((path.match(pattern) for pattern in patterns)) @@ -233,7 +217,16 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager -createAddonHelp(docsDir) +if (cssFile := Path("style.css")).is_file(): + cssPath = docsDir / cssFile + cssTarget = env.Command(str(cssPath), str(cssFile), Copy("$TARGET", "$SOURCE")) + env.Depends(addon, cssTarget) + +if (readmeFile := Path("readme.md")).is_file(): + readmePath = docsDir / buildVars.baseLanguage / readmeFile + readmeTarget = env.Command(str(readmePath), str(readmeFile), Copy("$TARGET", "$SOURCE")) + env.Depends(addon, readmeTarget) + for mdFile in env.Glob(docsDir/"*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. --- sconstruct | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/sconstruct b/sconstruct index 29e584c..bc6ff74 100644 --- a/sconstruct +++ b/sconstruct @@ -108,22 +108,6 @@ env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) -def createAddonHelp(docsDir: str|Path): - if isinstance(docsDir, str): - docsDir = Path(docsDir) - - cssFile = Path("style.css") - if cssFile.is_file(): - cssPath = docsDir / cssFile - cssTarget = env.Command(str(cssPath), str(cssFile), Copy("$TARGET", "$SOURCE")) - env.Depends(addon, cssTarget) - readmeFile = Path("readme.md") - if readmeFile.is_file(): - readmePath = docsDir / buildVars.baseLanguage / readmeFile - readmeTarget = env.Command(str(readmePath), str(readmeFile), Copy("$TARGET", "$SOURCE")) - env.Depends(addon, readmeTarget) - - def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: """Checks if the path, the first argument, does not match any of the patterns passed as the second argument.""" return not any((path.match(pattern) for pattern in patterns)) @@ -233,7 +217,16 @@ for file in pythonFiles: # Convert markdown files to html # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager -createAddonHelp(docsDir) +if (cssFile := Path("style.css")).is_file(): + cssPath = docsDir / cssFile + cssTarget = env.Command(str(cssPath), str(cssFile), Copy("$TARGET", "$SOURCE")) + env.Depends(addon, cssTarget) + +if (readmeFile := Path("readme.md")).is_file(): + readmePath = docsDir / buildVars.baseLanguage / readmeFile + readmeTarget = env.Command(str(readmePath), str(readmeFile), Copy("$TARGET", "$SOURCE")) + env.Depends(addon, readmeTarget) + for mdFile in env.Glob(docsDir/"*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. From a2068626cd15e2fc0cef526dfed51e4cf867e184 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 05:19:17 +0000 Subject: [PATCH 290/362] SConstruct: Refactored script Moved global variables after defining all functions. - Dirs (addonDir, localeDir, docsDir) - vars, env --- sconstruct | 72 +++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/sconstruct b/sconstruct index bc6ff74..cda3be5 100644 --- a/sconstruct +++ b/sconstruct @@ -33,11 +33,6 @@ sys.dont_write_bytecode = True import buildVars # NOQA: E402 -addonDir: Final = Path("addon/") -localeDir: Final = addonDir / "locale" -docsDir: Final = addonDir / "doc" - - def validateVersionNumber(key: str, val: str, _): # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. # Ignore all this if version number is not specified. @@ -50,32 +45,6 @@ def validateVersionNumber(key: str, val: str, _): raise ValueError(f"{key} (major.minor.patch) must be integers") -vars = Variables() -vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) -vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0", validateVersionNumber) -vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) -vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) - -env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool"]) -env.Append(**buildVars.addon_info) - -if env["dev"]: - from datetime import date - - versionTimestamp = date.today().strftime('%Y%m%d') - version = f"{versionTimestamp}.0.0" - env["addon_version"] = version - env["versionNumber"] = version - env["channel"] = "dev" -elif env["version"] is not None: - env["addon_version"] = env["version"] -if "channel" in env and env["channel"] is not None: - env["addon_updateChannel"] = env["channel"] - -buildVars.addon_info["addon_version"] = env["addon_version"] -buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] - - def addonGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: action = env.Action( lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, @@ -103,11 +72,6 @@ def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], return action -env["BUILDERS"]["NVDAAddon"] = Builder(generator=addonGenerator) -env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) -env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) - - def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: """Checks if the path, the first argument, does not match any of the patterns passed as the second argument.""" return not any((path.match(pattern) for pattern in patterns)) @@ -193,6 +157,42 @@ def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.E return [env.Entry(e) for pattern in patterns for e in rootdir.glob(pattern.lstrip('/'))] +addonDir: Final = Path("addon/") +localeDir: Final = addonDir / "locale" +docsDir: Final = addonDir / "doc" + + +vars = Variables() +vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) +vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0", validateVersionNumber) +vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) +vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) + +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool"]) +env.Append(**buildVars.addon_info) + +if env["dev"]: + from datetime import date + + versionTimestamp = date.today().strftime('%Y%m%d') + version = f"{versionTimestamp}.0.0" + env["addon_version"] = version + env["versionNumber"] = version + env["channel"] = "dev" +elif env["version"] is not None: + env["addon_version"] = env["version"] +if "channel" in env and env["channel"] is not None: + env["addon_updateChannel"] = env["channel"] + +buildVars.addon_info["addon_version"] = env["addon_version"] +buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] + + +env["BUILDERS"]["NVDAAddon"] = Builder(generator=addonGenerator) +env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) +env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) + + addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir)) From 16b0d3b95a19dd8de85e8fe65f343d25199bccf1 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 05:23:46 +0000 Subject: [PATCH 291/362] SConstruct: Update addonGenerator Converted addonGenerator to addonTool, since generators accept additional arguments that are not needed in this case. --- sconstruct | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index cda3be5..e5e427b 100644 --- a/sconstruct +++ b/sconstruct @@ -45,12 +45,16 @@ def validateVersionNumber(key: str, val: str, _): raise ValueError(f"{key} (major.minor.patch) must be integers") -def addonGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: +def addonTool(env: Environment): action = env.Action( lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, lambda target, source, env: f"Generating Addon {target[0]}", ) - return action + env["BUILDERS"]["NVDAAddon"] = Builder( + action=action, + suffix=".nvda-addon", + src_suffix="/" + ) def manifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: @@ -168,7 +172,7 @@ vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0 vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) -env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool"]) +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", addonTool]) env.Append(**buildVars.addon_info) if env["dev"]: @@ -188,7 +192,6 @@ buildVars.addon_info["addon_version"] = env["addon_version"] buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] -env["BUILDERS"]["NVDAAddon"] = Builder(generator=addonGenerator) env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) From 857867beb4ce138fbe6f526ee59c3d0ea74ceff6 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 06:09:11 +0000 Subject: [PATCH 292/362] SConstruct: Update manifestGenerator Converted manifestGenerator to manifestTool, since generators accept additional arguments that are not needed in this case. --- sconstruct | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index e5e427b..43484b6 100644 --- a/sconstruct +++ b/sconstruct @@ -57,12 +57,16 @@ def addonTool(env: Environment): ) -def manifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: +def manifestTool(env: Environment): action = env.Action( lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, lambda target, source, env: f"Generating manifest {target[0]}", ) - return action + env["BUILDERS"]["NVDAManifest"] = Builder( + action=action, + suffix=".ini", + src_siffix=".ini.tpl" + ) def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: @@ -172,7 +176,7 @@ vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0 vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) -env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", addonTool]) +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", addonTool, manifestTool]) env.Append(**buildVars.addon_info) if env["dev"]: @@ -192,7 +196,6 @@ buildVars.addon_info["addon_version"] = env["addon_version"] buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] -env["BUILDERS"]["NVDAManifest"] = Builder(generator=manifestGenerator) env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) From 6d85c81a45f09f72c31cf2663596213ce11177d7 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 06:43:16 +0000 Subject: [PATCH 293/362] SConstruct: Update addonTool The path patterns that need to be excluded from the .nvda-addon file are passed as arguments to the createAddonBundleFromPath function. --- sconstruct | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index 43484b6..8c79bc6 100644 --- a/sconstruct +++ b/sconstruct @@ -46,8 +46,11 @@ def validateVersionNumber(key: str, val: str, _): def addonTool(env: Environment): + env.SetDefault(excludePatterns=tuple()) action = env.Action( - lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, + lambda target, source, env: createAddonBundleFromPath( + source[0].abspath, target[0].abspath, env["excludePatterns"] + ) and None, lambda target, source, env: f"Generating Addon {target[0]}", ) env["BUILDERS"]["NVDAAddon"] = Builder( @@ -85,7 +88,7 @@ def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: return not any((path.match(pattern) for pattern in patterns)) -def createAddonBundleFromPath(path: str|Path, dest: str): +def createAddonBundleFromPath(path: str|Path, dest: str, excludePatterns: Iterable[str]): """Creates a bundle from a directory that contains an addon manifest file.""" if isinstance(path, str): path = Path(path) @@ -95,7 +98,7 @@ def createAddonBundleFromPath(path: str|Path, dest: str): if p.is_dir(): continue pathInBundle = p.relative_to(basedir) - if matchesNoPatterns(pathInBundle, buildVars.excludedFiles): + if matchesNoPatterns(pathInBundle, excludePatterns): z.write(p, pathInBundle) return dest @@ -200,7 +203,7 @@ env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifest addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") -addon = env.NVDAAddon(addonFile, env.Dir(addonDir)) +addon = env.NVDAAddon(addonFile, env.Dir(addonDir), excludePatterns=buildVars.excludedFiles) langDirs: list[FS.Dir] = [d for d in env.Glob(localeDir/"*/")] From 7fbfbd7adc877a70c063c462b82211f2635526a0 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 08:01:21 +0000 Subject: [PATCH 294/362] SConstruct, NVDATool: Created NVDATool The NVDAAddon builder has been moved to NVDATool. --- sconstruct | 38 +--------------------- site_scons/site_tools/NVDATool/__init__.py | 32 ++++++++++++++++++ site_scons/site_tools/NVDATool/addon.py | 24 ++++++++++++++ 3 files changed, 57 insertions(+), 37 deletions(-) create mode 100644 site_scons/site_tools/NVDATool/__init__.py create mode 100644 site_scons/site_tools/NVDATool/addon.py diff --git a/sconstruct b/sconstruct index 8c79bc6..be48f35 100644 --- a/sconstruct +++ b/sconstruct @@ -7,7 +7,6 @@ import codecs import gettext import os import os.path -import zipfile import sys from pathlib import Path from collections.abc import Iterable @@ -45,21 +44,6 @@ def validateVersionNumber(key: str, val: str, _): raise ValueError(f"{key} (major.minor.patch) must be integers") -def addonTool(env: Environment): - env.SetDefault(excludePatterns=tuple()) - action = env.Action( - lambda target, source, env: createAddonBundleFromPath( - source[0].abspath, target[0].abspath, env["excludePatterns"] - ) and None, - lambda target, source, env: f"Generating Addon {target[0]}", - ) - env["BUILDERS"]["NVDAAddon"] = Builder( - action=action, - suffix=".nvda-addon", - src_suffix="/" - ) - - def manifestTool(env: Environment): action = env.Action( lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, @@ -83,26 +67,6 @@ def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], return action -def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: - """Checks if the path, the first argument, does not match any of the patterns passed as the second argument.""" - return not any((path.match(pattern) for pattern in patterns)) - - -def createAddonBundleFromPath(path: str|Path, dest: str, excludePatterns: Iterable[str]): - """Creates a bundle from a directory that contains an addon manifest file.""" - if isinstance(path, str): - path = Path(path) - basedir = path.absolute() - with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as z: - for p in basedir.rglob("*"): - if p.is_dir(): - continue - pathInBundle = p.relative_to(basedir) - if matchesNoPatterns(pathInBundle, excludePatterns): - z.write(p, pathInBundle) - return dest - - def format_nested_section( section_name: str, data: Mapping[str, Mapping[str, str]] @@ -179,7 +143,7 @@ vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0 vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) -env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", addonTool, manifestTool]) +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", "NVDATool", manifestTool]) env.Append(**buildVars.addon_info) if env["dev"]: diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py new file mode 100644 index 0000000..1bd2d39 --- /dev/null +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -0,0 +1,32 @@ +""" +This tool generates NVDA extensions. + +Builders: + +- NVDAAddon: Creates a .nvda-addon zip file. Requires the `excludePatterns` environment variable. + +""" + +from SCons.Script import Environment, Builder + +from .addon import createAddonBundleFromPath + + + +def generate(env: Environment): + env.SetDefault(excludePatterns=tuple()) + + addonAction = env.Action( + lambda target, source, env: createAddonBundleFromPath( + source[0].abspath, target[0].abspath, env["excludePatterns"] + ) and None, + lambda target, source, env: f"Generating Addon {target[0]}", + ) + env["BUILDERS"]["NVDAAddon"] = Builder( + action=addonAction, + suffix=".nvda-addon", + src_suffix="/" + ) + +def exists(): + return True diff --git a/site_scons/site_tools/NVDATool/addon.py b/site_scons/site_tools/NVDATool/addon.py new file mode 100644 index 0000000..adc1424 --- /dev/null +++ b/site_scons/site_tools/NVDATool/addon.py @@ -0,0 +1,24 @@ +import zipfile +from collections.abc import Iterable +from pathlib import Path + + + +def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: + """Checks if the path, the first argument, does not match any of the patterns passed as the second argument.""" + return not any((path.match(pattern) for pattern in patterns)) + + +def createAddonBundleFromPath(path: str|Path, dest: str, excludePatterns: Iterable[str]): + """Creates a bundle from a directory that contains an addon manifest file.""" + if isinstance(path, str): + path = Path(path) + basedir = path.absolute() + with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as z: + for p in basedir.rglob("*"): + if p.is_dir(): + continue + pathInBundle = p.relative_to(basedir) + if matchesNoPatterns(pathInBundle, excludePatterns): + z.write(p, pathInBundle) + return dest From fced6949fecc8b9e3e2aa36edbc98da342e70dd2 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 09:56:22 +0000 Subject: [PATCH 295/362] buildVars, NVDATool: Moved AddonInfo class to NVDATool --- buildVars.py | 18 +----------------- site_scons/site_tools/NVDATool/typings.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) create mode 100644 site_scons/site_tools/NVDATool/typings.py diff --git a/buildVars.py b/buildVars.py index 4eaaef1..b50c5e1 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,7 +1,7 @@ # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. -from typing import TypedDict +from site_scons.site_tools.NVDATool.typings import AddonInfo # Since some strings in `addon_info` are translatable, # we need to include them in the .po files. @@ -12,22 +12,6 @@ def _(arg: str) -> str: return arg -# A typed dictionary for storing meta information about add-on. -class AddonInfo(TypedDict): - addon_name: str - addon_summary: str - addon_description: str - addon_version: str - addon_author: str - addon_url: str|None - addon_sourceURL: str|None - addon_docFileName: str - addon_minimumNVDAVersion: str|None - addon_lastTestedNVDAVersion: str|None - addon_updateChannel: str|None - addon_license: str|None - addon_licenseURL: str|None - # Add-on information variables addon_info: AddonInfo = { # add-on Name/identifier, internal for NVDA diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py new file mode 100644 index 0000000..3309cc8 --- /dev/null +++ b/site_scons/site_tools/NVDATool/typings.py @@ -0,0 +1,18 @@ +from typing import TypedDict + + + +class AddonInfo(TypedDict): + addon_name: str + addon_summary: str + addon_description: str + addon_version: str + addon_author: str + addon_url: str|None + addon_sourceURL: str|None + addon_docFileName: str + addon_minimumNVDAVersion: str|None + addon_lastTestedNVDAVersion: str|None + addon_updateChannel: str|None + addon_license: str|None + addon_licenseURL: str|None From 958a157af48e92f81eb805cea3f2e038d6acfe42 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 10:08:41 +0000 Subject: [PATCH 296/362] buildVars, NVDATool: Update brl tabs & sym dicts type hints Added to NVDATool.typings: - BrailleTableAttributes (TypedDict) - BrailleTables (dict) - SymbolDictionaryAttributes (TypedDict) - SymbolDictionaries (dict) Used above dicts types in buildVars --- buildVars.py | 6 +++--- site_scons/site_tools/NVDATool/typings.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/buildVars.py b/buildVars.py index b50c5e1..33401e0 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,7 +1,7 @@ # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. -from site_scons.site_tools.NVDATool.typings import AddonInfo +from site_scons.site_tools.NVDATool.typings import AddonInfo, BrailleTables, SymbolDictionaries # Since some strings in `addon_info` are translatable, # we need to include them in the .po files. @@ -88,7 +88,7 @@ def _(arg: str) -> str: # contracted (contracted (True) or uncontracted (False) braille code), # output (shown in output table list), # input (shown in input table list). -brailleTables: dict[str, dict[str, str]] = {} +brailleTables: BrailleTables = {} # Custom speech symbol dictionaries # Symbol dictionary files reside in the locale folder, e.g. `locale\en`, and are named `symbols-.dic`. @@ -97,4 +97,4 @@ def _(arg: str) -> str: # with keys inside recording the following attributes: # displayName (name of the speech dictionary shown to users and translatable), # mandatory (True when always enabled, False when not. -symbolDictionaries: dict[str, dict[str, str]] = {} +symbolDictionaries: SymbolDictionaries = {} diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py index 3309cc8..a76aa9c 100644 --- a/site_scons/site_tools/NVDATool/typings.py +++ b/site_scons/site_tools/NVDATool/typings.py @@ -16,3 +16,19 @@ class AddonInfo(TypedDict): addon_updateChannel: str|None addon_license: str|None addon_licenseURL: str|None + + +class BrailleTableAttributes(TypedDict): + displayName: str + contracted: bool + output: bool + input: bool + + +class SymbolDictionaryAttributes(TypedDict): + displayName: str + mandatory: bool + + +BrailleTables = dict[str, BrailleTableAttributes] +SymbolDictionaries = dict[str, SymbolDictionaryAttributes] From c769cac0458d0f42ff39227fe1e974f13cdbee6a Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 10:26:33 +0000 Subject: [PATCH 297/362] SConstruct: Fixed import Mapping typing.Mapping is deprecated --- sconstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index be48f35..11334e3 100644 --- a/sconstruct +++ b/sconstruct @@ -9,8 +9,8 @@ import os import os.path import sys from pathlib import Path -from collections.abc import Iterable -from typing import Final, Mapping +from collections.abc import Iterable, Mapping +from typing import Final # While names imported below are available by default in every SConscript # Linters aren't aware about them. From b5ed0ed87f76fafd7d1c118f65bac58552fb9982 Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 10:49:31 +0000 Subject: [PATCH 298/362] NVDATool: Added Strable protocol --- site_scons/site_tools/NVDATool/typings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py index a76aa9c..c4d74ea 100644 --- a/site_scons/site_tools/NVDATool/typings.py +++ b/site_scons/site_tools/NVDATool/typings.py @@ -1,4 +1,4 @@ -from typing import TypedDict +from typing import TypedDict, Protocol, override @@ -32,3 +32,8 @@ class SymbolDictionaryAttributes(TypedDict): BrailleTables = dict[str, BrailleTableAttributes] SymbolDictionaries = dict[str, SymbolDictionaryAttributes] + + +class Strable(Protocol): + @override + def __str__(self) -> str: ... From ea7d99d3dabbdddc2d63294bfe8800313deb85dd Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 10:57:14 +0000 Subject: [PATCH 299/362] SConstruct: Updated functions signatures, used Strable - format_nested_section - generateTranslatedManifest._format_section_only_with_displayName --- sconstruct | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sconstruct b/sconstruct index 11334e3..05e33ae 100644 --- a/sconstruct +++ b/sconstruct @@ -30,6 +30,7 @@ EnsurePythonVersion(3, 10) sys.dont_write_bytecode = True import buildVars # NOQA: E402 +from site_scons.site_tools.NVDATool.typings import Strable # NOQA: E402 def validateVersionNumber(key: str, val: str, _): @@ -69,7 +70,7 @@ def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], def format_nested_section( section_name: str, - data: Mapping[str, Mapping[str, str]] + data: Mapping[str, Mapping[str, Strable]] ) -> str: lines = [f"\n[{section_name}]"] for item_name, inner_dict in data.items(): @@ -107,7 +108,7 @@ def generateTranslatedManifest(source: str, language: str, dest: str): manifest_template = f.read() manifest = manifest_template.format(**vars) - def _format_section_only_with_displayName(section_name: str, data: Mapping[str, Mapping[str, str]]) -> str: + def _format_section_only_with_displayName(section_name: str, data: Mapping[str, Mapping[str, Strable]]) -> str: lines = [f"\n[{section_name}]"] for item, inner_dict in data.items(): lines.append(f"[[{item}]]") From 7ef5669c0cf45bed652f35c08af7af5e06ecd0fb Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 14:54:41 +0000 Subject: [PATCH 300/362] SConstruct: Updated generateManifest All parameters are passed to the function arguments. --- sconstruct | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/sconstruct b/sconstruct index 05e33ae..cb6e410 100644 --- a/sconstruct +++ b/sconstruct @@ -30,7 +30,7 @@ EnsurePythonVersion(3, 10) sys.dont_write_bytecode = True import buildVars # NOQA: E402 -from site_scons.site_tools.NVDATool.typings import Strable # NOQA: E402 +from site_scons.site_tools.NVDATool.typings import AddonInfo, BrailleTables, SymbolDictionaries, Strable # NOQA: E402 def validateVersionNumber(key: str, val: str, _): @@ -46,8 +46,17 @@ def validateVersionNumber(key: str, val: str, _): def manifestTool(env: Environment): + env.SetDefault(brailleTables={}) + env.SetDefault(symbolDictionaries={}) + action = env.Action( - lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, + lambda target, source, env: generateManifest( + source[0].abspath, + target[0].abspath, + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + ) and None, lambda target, source, env: f"Generating manifest {target[0]}", ) env["BUILDERS"]["NVDAManifest"] = Builder( @@ -80,20 +89,25 @@ def format_nested_section( return "\n".join(lines) + "\n" -def generateManifest(source: str, dest: str): +def generateManifest( + source: str, + dest: str, + addon_info: AddonInfo, + brailleTables: BrailleTables, + symbolDictionaries: SymbolDictionaries, + ): # Prepare the root manifest section - addon_info = buildVars.addon_info with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() manifest = manifest_template.format(**addon_info) # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if hasattr(buildVars, "brailleTables"): - manifest += format_nested_section("brailleTables", buildVars.brailleTables) + if brailleTables: + manifest += format_nested_section("brailleTables", brailleTables) # Custom speech symbol dictionaries - if hasattr(buildVars, "symbolDictionaries"): - manifest += format_nested_section("symbolDictionaries", buildVars.symbolDictionaries) + if symbolDictionaries: + manifest += format_nested_section("symbolDictionaries", symbolDictionaries) with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) @@ -228,7 +242,10 @@ env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path -manifest = env.NVDAManifest(env.File(addonDir/"manifest.ini"), "manifest.ini.tpl") +manifest = env.NVDAManifest(env.File(addonDir/"manifest.ini"), "manifest.ini.tpl", + addon_info=buildVars.addon_info, + brailleTables=buildVars.brailleTables, + symbolDictionaries=buildVars.symbolDictionaries) # Ensure manifest is rebuilt if buildVars is updated. env.Depends(manifest, "buildVars.py") From ae3af0d98f36360851ca8da980ef184a78b726db Mon Sep 17 00:00:00 2001 From: balaraz Date: Wed, 30 Jul 2025 15:00:39 +0000 Subject: [PATCH 301/362] SConstruct: Updated generateTranslatedManifest - All parameters are passed to the function arguments. - The parameters are set via env.Append. --- sconstruct | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/sconstruct b/sconstruct index cb6e410..14d4e7b 100644 --- a/sconstruct +++ b/sconstruct @@ -70,8 +70,14 @@ def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], dir = Path(str(source[0])).absolute().parents[1] lang = dir.name action = env.Action( - lambda target, source, env: generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) - and None, + lambda target, source, env: generateTranslatedManifest( + source[1].abspath, + target[0].abspath, + lang, env["localedir"], + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + ) and None, lambda target, source, env: f"Generating translated manifest {target[0]}", ) return action @@ -113,11 +119,19 @@ def generateManifest( f.write(manifest) -def generateTranslatedManifest(source: str, language: str, dest: str): +def generateTranslatedManifest( + source: str, + dest: str, + language: str, + localeDir: str, + addon_info: AddonInfo, + brailleTables: BrailleTables, + symbolDictionaries: SymbolDictionaries, + ): _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext vars: dict[str, str] = {} for var in ("addon_summary", "addon_description"): - vars[var] = _(buildVars.addon_info[var]) + vars[var] = _(addon_info[var]) with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() manifest = manifest_template.format(**vars) @@ -132,12 +146,12 @@ def generateTranslatedManifest(source: str, language: str, dest: str): # Add additional manifest sections such as custom braile tables # Custom braille translation tables - if tables := getattr(buildVars, "brailleTables", None): - manifest += _format_section_only_with_displayName("brailleTables", tables) + if brailleTables: + manifest += _format_section_only_with_displayName("brailleTables", brailleTables) # Custom speech symbol dictionaries - if dicts := getattr(buildVars, "symbolDictionaries", None): - manifest += _format_section_only_with_displayName("symbolDictionaries", dicts) + if symbolDictionaries: + manifest += _format_section_only_with_displayName("symbolDictionaries", symbolDictionaries) with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) @@ -159,7 +173,13 @@ vars.Add(BoolVariable("dev", "Whether this is a daily development version", Fals vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", "NVDATool", manifestTool]) -env.Append(**buildVars.addon_info) +env.Append( + addon_info=buildVars.addon_info, + localedir=localeDir, + brailleTables=buildVars.brailleTables, + symbolDictionaries=buildVars.symbolDictionaries, + **buildVars.addon_info +) if env["dev"]: from datetime import date @@ -242,10 +262,7 @@ env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path -manifest = env.NVDAManifest(env.File(addonDir/"manifest.ini"), "manifest.ini.tpl", - addon_info=buildVars.addon_info, - brailleTables=buildVars.brailleTables, - symbolDictionaries=buildVars.symbolDictionaries) +manifest = env.NVDAManifest(env.File(addonDir/"manifest.ini"), "manifest.ini.tpl") # Ensure manifest is rebuilt if buildVars is updated. env.Depends(manifest, "buildVars.py") From 57e90816ed79e54871e1b2fb18dae842c5dd7321 Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 31 Jul 2025 08:51:54 +0000 Subject: [PATCH 302/362] SConstruct, NVDATool: Moved manifest generators to NVDATool - manifestTool insert to NVDATool.generate - translatedManifestGenrator moved to NVDATool.__init__ - generateManifest & generateTranslatedManifest moved to NVDATool.manifests --- sconstruct | 123 +------------------- site_scons/site_tools/NVDATool/__init__.py | 54 +++++++++ site_scons/site_tools/NVDATool/manifests.py | 81 +++++++++++++ 3 files changed, 137 insertions(+), 121 deletions(-) create mode 100644 site_scons/site_tools/NVDATool/manifests.py diff --git a/sconstruct b/sconstruct index 14d4e7b..f4d4ac4 100644 --- a/sconstruct +++ b/sconstruct @@ -3,13 +3,11 @@ # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. -import codecs -import gettext import os import os.path import sys from pathlib import Path -from collections.abc import Iterable, Mapping +from collections.abc import Iterable from typing import Final # While names imported below are available by default in every SConscript @@ -20,7 +18,6 @@ from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environme # Imports for type hints from SCons.Node import FS -from SCons.Action import CommandAction # Add-on localization exchange facility and the template requires Python 3.10. # For best practice, use Python 3.11 or later to align with NVDA development. @@ -30,7 +27,6 @@ EnsurePythonVersion(3, 10) sys.dont_write_bytecode = True import buildVars # NOQA: E402 -from site_scons.site_tools.NVDATool.typings import AddonInfo, BrailleTables, SymbolDictionaries, Strable # NOQA: E402 def validateVersionNumber(key: str, val: str, _): @@ -45,118 +41,6 @@ def validateVersionNumber(key: str, val: str, _): raise ValueError(f"{key} (major.minor.patch) must be integers") -def manifestTool(env: Environment): - env.SetDefault(brailleTables={}) - env.SetDefault(symbolDictionaries={}) - - action = env.Action( - lambda target, source, env: generateManifest( - source[0].abspath, - target[0].abspath, - addon_info=env["addon_info"], - brailleTables=env["brailleTables"], - symbolDictionaries=env["symbolDictionaries"], - ) and None, - lambda target, source, env: f"Generating manifest {target[0]}", - ) - env["BUILDERS"]["NVDAManifest"] = Builder( - action=action, - suffix=".ini", - src_siffix=".ini.tpl" - ) - - -def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: - dir = Path(str(source[0])).absolute().parents[1] - lang = dir.name - action = env.Action( - lambda target, source, env: generateTranslatedManifest( - source[1].abspath, - target[0].abspath, - lang, env["localedir"], - addon_info=env["addon_info"], - brailleTables=env["brailleTables"], - symbolDictionaries=env["symbolDictionaries"], - ) and None, - lambda target, source, env: f"Generating translated manifest {target[0]}", - ) - return action - - -def format_nested_section( - section_name: str, - data: Mapping[str, Mapping[str, Strable]] -) -> str: - lines = [f"\n[{section_name}]"] - for item_name, inner_dict in data.items(): - lines.append(f"[[{item_name}]]") - for key, val in inner_dict.items(): - lines.append(f"{key} = {val}") - return "\n".join(lines) + "\n" - - -def generateManifest( - source: str, - dest: str, - addon_info: AddonInfo, - brailleTables: BrailleTables, - symbolDictionaries: SymbolDictionaries, - ): - # Prepare the root manifest section - with codecs.open(source, "r", "utf-8") as f: - manifest_template = f.read() - manifest = manifest_template.format(**addon_info) - # Add additional manifest sections such as custom braile tables - # Custom braille translation tables - if brailleTables: - manifest += format_nested_section("brailleTables", brailleTables) - - # Custom speech symbol dictionaries - if symbolDictionaries: - manifest += format_nested_section("symbolDictionaries", symbolDictionaries) - - with codecs.open(dest, "w", "utf-8") as f: - f.write(manifest) - - -def generateTranslatedManifest( - source: str, - dest: str, - language: str, - localeDir: str, - addon_info: AddonInfo, - brailleTables: BrailleTables, - symbolDictionaries: SymbolDictionaries, - ): - _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext - vars: dict[str, str] = {} - for var in ("addon_summary", "addon_description"): - vars[var] = _(addon_info[var]) - with codecs.open(source, "r", "utf-8") as f: - manifest_template = f.read() - manifest = manifest_template.format(**vars) - - def _format_section_only_with_displayName(section_name: str, data: Mapping[str, Mapping[str, Strable]]) -> str: - lines = [f"\n[{section_name}]"] - for item, inner_dict in data.items(): - lines.append(f"[[{item}]]") - # Fetch display name only. - lines.append(f"displayName = {_(inner_dict['displayName'])}") - return "\n".join(lines) + "\n" - - # Add additional manifest sections such as custom braile tables - # Custom braille translation tables - if brailleTables: - manifest += _format_section_only_with_displayName("brailleTables", brailleTables) - - # Custom speech symbol dictionaries - if symbolDictionaries: - manifest += _format_section_only_with_displayName("symbolDictionaries", symbolDictionaries) - - with codecs.open(dest, "w", "utf-8") as f: - f.write(manifest) - - def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.Entry]: return [env.Entry(e) for pattern in patterns for e in rootdir.glob(pattern.lstrip('/'))] @@ -172,7 +56,7 @@ vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0 vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) -env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", "NVDATool", manifestTool]) +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", "NVDATool"]) env.Append( addon_info=buildVars.addon_info, localedir=localeDir, @@ -198,9 +82,6 @@ buildVars.addon_info["addon_version"] = env["addon_version"] buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] -env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) - - addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir), excludePatterns=buildVars.excludedFiles) diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 1bd2d39..997f05a 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -4,12 +4,44 @@ Builders: - NVDAAddon: Creates a .nvda-addon zip file. Requires the `excludePatterns` environment variable. +- NVDAManifest: Creates the manifest.ini file. +- NVDATranslatedManifest: Creates the manifest.ini file with only translated information. + +The following environment variables are required to create the manifest: + +- addon_info: .typing.AddonInfo +- lcaledir: str | pathlib.Path +- brailleTables: .typings.BrailleTables +- symbolDictionaries: .typings.SymbolDictionaries """ +from pathlib import Path + from SCons.Script import Environment, Builder +from SCons.Node import FS +from SCons.Action import CommandAction from .addon import createAddonBundleFromPath +from .manifests import generateManifest, generateTranslatedManifest + + + +def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: + dir = Path(str(source[0])).absolute().parents[1] + lang = dir.name + action = env.Action( + lambda target, source, env: generateTranslatedManifest( + source[1].abspath, + target[0].abspath, + lang, env["localedir"], + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + ) and None, + lambda target, source, env: f"Generating translated manifest {target[0]}", + ) + return action @@ -28,5 +60,27 @@ def generate(env: Environment): src_suffix="/" ) + env.SetDefault(brailleTables={}) + env.SetDefault(symbolDictionaries={}) + + manifestAction = env.Action( + lambda target, source, env: generateManifest( + source[0].abspath, + target[0].abspath, + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + ) and None, + lambda target, source, env: f"Generating manifest {target[0]}", + ) + env["BUILDERS"]["NVDAManifest"] = Builder( + action=manifestAction, + suffix=".ini", + src_siffix=".ini.tpl" + ) + + env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) + + def exists(): return True diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py new file mode 100644 index 0000000..b1b07bc --- /dev/null +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -0,0 +1,81 @@ + +import codecs +import gettext +from collections.abc import Mapping + +from site_scons.site_tools.NVDATool.typings import AddonInfo, BrailleTables, SymbolDictionaries, Strable # NOQA: E402 + + + +def format_nested_section( + section_name: str, + data: Mapping[str, Mapping[str, Strable]] +) -> str: + lines = [f"\n[{section_name}]"] + for item_name, inner_dict in data.items(): + lines.append(f"[[{item_name}]]") + for key, val in inner_dict.items(): + lines.append(f"{key} = {val}") + return "\n".join(lines) + "\n" + + +def generateManifest( + source: str, + dest: str, + addon_info: AddonInfo, + brailleTables: BrailleTables, + symbolDictionaries: SymbolDictionaries, + ): + # Prepare the root manifest section + with codecs.open(source, "r", "utf-8") as f: + manifest_template = f.read() + manifest = manifest_template.format(**addon_info) + # Add additional manifest sections such as custom braile tables + # Custom braille translation tables + if brailleTables: + manifest += format_nested_section("brailleTables", brailleTables) + + # Custom speech symbol dictionaries + if symbolDictionaries: + manifest += format_nested_section("symbolDictionaries", symbolDictionaries) + + with codecs.open(dest, "w", "utf-8") as f: + f.write(manifest) + + +def generateTranslatedManifest( + source: str, + dest: str, + language: str, + localeDir: str, + addon_info: AddonInfo, + brailleTables: BrailleTables, + symbolDictionaries: SymbolDictionaries, + ): + _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext + vars: dict[str, str] = {} + for var in ("addon_summary", "addon_description"): + vars[var] = _(addon_info[var]) + with codecs.open(source, "r", "utf-8") as f: + manifest_template = f.read() + manifest = manifest_template.format(**vars) + + def _format_section_only_with_displayName(section_name: str, data: Mapping[str, Mapping[str, Strable]]) -> str: + lines = [f"\n[{section_name}]"] + for item, inner_dict in data.items(): + lines.append(f"[[{item}]]") + # Fetch display name only. + lines.append(f"displayName = {_(str(inner_dict['displayName']))}") + return "\n".join(lines) + "\n" + + # Add additional manifest sections such as custom braile tables + # Custom braille translation tables + if brailleTables: + manifest += _format_section_only_with_displayName("brailleTables", brailleTables) + + # Custom speech symbol dictionaries + if symbolDictionaries: + manifest += _format_section_only_with_displayName("symbolDictionaries", symbolDictionaries) + + with codecs.open(dest, "w", "utf-8") as f: + f.write(manifest) From d7545ba25fc59c8d542aa315551d8c09422f5dee Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 31 Jul 2025 15:10:53 +0000 Subject: [PATCH 303/362] SConstruct, NVDATool: Updated translatedManifestGenrator --- sconstruct | 1 - site_scons/site_tools/NVDATool/__init__.py | 5 +---- site_scons/site_tools/NVDATool/manifests.py | 7 ++++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/sconstruct b/sconstruct index f4d4ac4..785e4ca 100644 --- a/sconstruct +++ b/sconstruct @@ -59,7 +59,6 @@ vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", "NVDATool"]) env.Append( addon_info=buildVars.addon_info, - localedir=localeDir, brailleTables=buildVars.brailleTables, symbolDictionaries=buildVars.symbolDictionaries, **buildVars.addon_info diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 997f05a..9df217e 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -10,7 +10,6 @@ The following environment variables are required to create the manifest: - addon_info: .typing.AddonInfo -- lcaledir: str | pathlib.Path - brailleTables: .typings.BrailleTables - symbolDictionaries: .typings.SymbolDictionaries @@ -28,13 +27,11 @@ def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: - dir = Path(str(source[0])).absolute().parents[1] - lang = dir.name action = env.Action( lambda target, source, env: generateTranslatedManifest( source[1].abspath, target[0].abspath, - lang, env["localedir"], + mo=source[0].abspath, addon_info=env["addon_info"], brailleTables=env["brailleTables"], symbolDictionaries=env["symbolDictionaries"], diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py index b1b07bc..7df44b6 100644 --- a/site_scons/site_tools/NVDATool/manifests.py +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -46,13 +46,14 @@ def generateManifest( def generateTranslatedManifest( source: str, dest: str, - language: str, - localeDir: str, + *, + mo: str, addon_info: AddonInfo, brailleTables: BrailleTables, symbolDictionaries: SymbolDictionaries, ): - _ = gettext.translation("nvda", localedir=localeDir, languages=[language]).gettext + with open(mo, "rb") as f: + _ = gettext.GNUTranslations(f).gettext vars: dict[str, str] = {} for var in ("addon_summary", "addon_description"): vars[var] = _(addon_info[var]) From d5e3462e1a75035163a027f9bcdd19382dfe5561 Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 31 Jul 2025 15:19:35 +0000 Subject: [PATCH 304/362] NVDATOOl: Removed translatedManifestGenerator Moved action to NVDATool.generate function --- site_scons/site_tools/NVDATool/__init__.py | 36 ++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 9df217e..dcfe8d2 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -18,30 +18,12 @@ from pathlib import Path from SCons.Script import Environment, Builder -from SCons.Node import FS -from SCons.Action import CommandAction from .addon import createAddonBundleFromPath from .manifests import generateManifest, generateTranslatedManifest -def translatedManifestGenerator(target: list[FS.Entry], source: list[FS.Entry], env: Environment, for_signature: bool) -> CommandAction: - action = env.Action( - lambda target, source, env: generateTranslatedManifest( - source[1].abspath, - target[0].abspath, - mo=source[0].abspath, - addon_info=env["addon_info"], - brailleTables=env["brailleTables"], - symbolDictionaries=env["symbolDictionaries"], - ) and None, - lambda target, source, env: f"Generating translated manifest {target[0]}", - ) - return action - - - def generate(env: Environment): env.SetDefault(excludePatterns=tuple()) @@ -76,7 +58,23 @@ def generate(env: Environment): src_siffix=".ini.tpl" ) - env["BUILDERS"]["NVDATranslatedManifest"] = Builder(generator=translatedManifestGenerator) + translatedManifestAction = env.Action( + lambda target, source, env: generateTranslatedManifest( + source[1].abspath, + target[0].abspath, + mo=source[0].abspath, + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + ) and None, + lambda target, source, env: f"Generating translated manifest {target[0]}", + ) + + env["BUILDERS"]["NVDATranslatedManifest"] = Builder( + action=translatedManifestAction, + suffix=".ini", + src_siffix=".ini.tpl" + ) def exists(): From 0f4c508efac88d6b2db950f2fcde2ffa70ac0541 Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 31 Jul 2025 15:56:47 +0000 Subject: [PATCH 305/362] NVDATool: Remove typing.override from typings.py --- site_scons/site_tools/NVDATool/typings.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py index c4d74ea..e7b1791 100644 --- a/site_scons/site_tools/NVDATool/typings.py +++ b/site_scons/site_tools/NVDATool/typings.py @@ -1,4 +1,4 @@ -from typing import TypedDict, Protocol, override +from typing import TypedDict, Protocol @@ -35,5 +35,4 @@ class SymbolDictionaryAttributes(TypedDict): class Strable(Protocol): - @override def __str__(self) -> str: ... From bc09b7167e46bb8e8247f4f5ea28231737997024 Mon Sep 17 00:00:00 2001 From: balaraz Date: Thu, 31 Jul 2025 18:28:17 +0000 Subject: [PATCH 306/362] SConstruct: Removed unneeded update buildVars.addon_info --- sconstruct | 3 --- 1 file changed, 3 deletions(-) diff --git a/sconstruct b/sconstruct index 785e4ca..021eaf0 100644 --- a/sconstruct +++ b/sconstruct @@ -77,9 +77,6 @@ elif env["version"] is not None: if "channel" in env and env["channel"] is not None: env["addon_updateChannel"] = env["channel"] -buildVars.addon_info["addon_version"] = env["addon_version"] -buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] - addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir), excludePatterns=buildVars.excludedFiles) From e7e900fac3e5f3cde9a72c427dffc0c69a3a1dc8 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 08:28:27 +0000 Subject: [PATCH 307/362] SConstruct, mdTool, NVDATool: Removed mdTool Moved md2html builder to NVDATool, as it is not a pure HTML to Markdown converter. Specific actions for NVDA add-ons are present. --- sconstruct | 2 +- site_scons/site_tools/NVDATool/__init__.py | 32 +++++++++++++ .../{mdTool/__init__.py => NVDATool/docs.py} | 47 ------------------- 3 files changed, 33 insertions(+), 48 deletions(-) rename site_scons/site_tools/{mdTool/__init__.py => NVDATool/docs.py} (58%) diff --git a/sconstruct b/sconstruct index 021eaf0..8c3e82d 100644 --- a/sconstruct +++ b/sconstruct @@ -56,7 +56,7 @@ vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0 vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) -env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "mdTool", "NVDATool"]) +env = Environment(variables=vars, ENV=os.environ, tools=["gettexttool", "NVDATool"]) env.Append( addon_info=buildVars.addon_info, brailleTables=buildVars.brailleTables, diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index dcfe8d2..95677be 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -6,6 +6,7 @@ - NVDAAddon: Creates a .nvda-addon zip file. Requires the `excludePatterns` environment variable. - NVDAManifest: Creates the manifest.ini file. - NVDATranslatedManifest: Creates the manifest.ini file with only translated information. +- md2html: Build HTML from Markdown The following environment variables are required to create the manifest: @@ -13,6 +14,14 @@ - brailleTables: .typings.BrailleTables - symbolDictionaries: .typings.SymbolDictionaries +The following environment variables are required to build the HTML: + +- localeDir: str +- localeFileName: str +- mdExtensions: list[str] +- addon_summary: str +- addon_version: str + """ from pathlib import Path @@ -21,6 +30,7 @@ from .addon import createAddonBundleFromPath from .manifests import generateManifest, generateTranslatedManifest +from .docs import md2html @@ -76,6 +86,28 @@ def generate(env: Environment): src_siffix=".ini.tpl" ) + env.SetDefault(localeDir = Path("locale/")) + env.SetDefault(localeFileName = "messages") + env.SetDefault(mdExtensions = {}) + + mdAction = env.Action( + lambda target, source, env: md2html( + source[0].path, + target[0].path, + localeDir=env["localeDir"], + loacleFileName=env["localeFileName"], + mdExtensions=env["mdExtensions"], + addonSummary=env["addon_summary"], + addonVersion=env["addon_version"] + ) and None, + lambda target, source, env: f"Generating {target[0]}", + ) + env["BUILDERS"]["md2html"] = env.Builder( + action=mdAction, + suffix=".html", + src_suffix=".md", + ) + def exists(): return True diff --git a/site_scons/site_tools/mdTool/__init__.py b/site_scons/site_tools/NVDATool/docs.py similarity index 58% rename from site_scons/site_tools/mdTool/__init__.py rename to site_scons/site_tools/NVDATool/docs.py index 5547237..ade5dcb 100644 --- a/site_scons/site_tools/mdTool/__init__.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -1,27 +1,9 @@ -""" -This tool allows you to generate HTML files from Markdown. - -Adds the following Builder to the constructed environment: - -- md2html: Build HTML from Markdown - -The following variables are required in the environment: - -- localeDir -- localeFileName -- mdExtensions -- addon_summary -- addon_version - - -""" import gettext import codecs from pathlib import Path import markdown -from SCons.Script import Environment @@ -77,32 +59,3 @@ def md2html( ) with codecs.open(dest, "w", "utf-8") as f: f.write(docText) - - -def generate(env: Environment): - env.SetDefault(localeDir = Path("locale/")) - env.SetDefault(localeFileName = "messages") - env.SetDefault(mdExtensions = {}) - - mdAction = env.Action( - lambda target, source, env: md2html( - source[0].path, - target[0].path, - localeDir=env["localeDir"], - loacleFileName=env["localeFileName"], - mdExtensions=env["mdExtensions"], - addonSummary=env["addon_summary"], - addonVersion=env["addon_version"] - ) and None, - lambda target, source, env: f"Generating {target[0]}", - ) - mdBuilder = env.Builder( - action=mdAction, - suffix=".html", - src_suffix=".md", - ) - env["BUILDERS"]["md2html"] = mdBuilder - - -def exists(): - return True From 1a0968d5d8f537c0a0b66b386b8a61329fe0a05a Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 09:40:42 +0000 Subject: [PATCH 308/362] NVDATool: Updated md2html Replaced separate variables addon_summary and addon_version with one common addon_info --- site_scons/site_tools/NVDATool/__init__.py | 6 ++---- site_scons/site_tools/NVDATool/docs.py | 11 ++++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 95677be..79d5b68 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -19,8 +19,7 @@ - localeDir: str - localeFileName: str - mdExtensions: list[str] -- addon_summary: str -- addon_version: str +- addon_info: .typings.AddonInfo """ @@ -97,8 +96,7 @@ def generate(env: Environment): localeDir=env["localeDir"], loacleFileName=env["localeFileName"], mdExtensions=env["mdExtensions"], - addonSummary=env["addon_summary"], - addonVersion=env["addon_version"] + addon_info=env["addon_info"], ) and None, lambda target, source, env: f"Generating {target[0]}", ) diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index ade5dcb..6c4f607 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -5,6 +5,8 @@ import markdown +from .typings import AddonInfo + def md2html( @@ -14,8 +16,7 @@ def md2html( localeDir: Path, loacleFileName: str, mdExtensions: list[str], - addonSummary: str, - addonVersion: str + addon_info: AddonInfo ): if isinstance(source, str): source = Path(source) @@ -29,10 +30,10 @@ def md2html( localedir=localeDir, languages=[localeLang] ).gettext - summary = _(addonSummary) + summary = _(addon_info["addon_summary"]) except Exception: - summary = addonSummary - title = f"{summary} {addonVersion}" + summary = addon_info["addon_summary"] + title = f"{summary} {addon_info["addon_version"]}" headerDic = { '[[!meta title="': "# ", '"]]': " #", From 933418916a3c5a95d89d90f36872774510df5b6f Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 10:20:32 +0000 Subject: [PATCH 309/362] buildVars, NVDATool: Moved _ func to NVDATool.utils --- buildVars.py | 5 ++--- site_scons/site_tools/NVDATool/utils.py | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 site_scons/site_tools/NVDATool/utils.py diff --git a/buildVars.py b/buildVars.py index 33401e0..b57a438 100644 --- a/buildVars.py +++ b/buildVars.py @@ -6,10 +6,9 @@ # Since some strings in `addon_info` are translatable, # we need to include them in the .po files. # Gettext recognizes only strings given as parameters to the `_` function. -# To avoid initializing translations in this module we simply roll our own "fake" `_` function +# To avoid initializing translations in this module we simply import a "fake" `_` function # which returns whatever is given to it as an argument. -def _(arg: str) -> str: - return arg +from site_scons.site_tools.NVDATool.utils import _ # Add-on information variables diff --git a/site_scons/site_tools/NVDATool/utils.py b/site_scons/site_tools/NVDATool/utils.py new file mode 100644 index 0000000..326d394 --- /dev/null +++ b/site_scons/site_tools/NVDATool/utils.py @@ -0,0 +1,7 @@ + +def _(arg: str) -> str: + """ + A function that passes the string to it without doing anything to it. + Needed for recognizing strings for translation by Gettext. + """ + return arg From f3347a08f46af205d55227ef4aeeb52fe3d78758 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 10:25:43 +0000 Subject: [PATCH 310/362] NVDATool: Refactored import typings in NVDATool.manifests --- site_scons/site_tools/NVDATool/manifests.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py index 7df44b6..9317419 100644 --- a/site_scons/site_tools/NVDATool/manifests.py +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -3,8 +3,7 @@ import gettext from collections.abc import Mapping -from site_scons.site_tools.NVDATool.typings import AddonInfo, BrailleTables, SymbolDictionaries, Strable # NOQA: E402 - +from .typings import AddonInfo, BrailleTables, SymbolDictionaries, Strable def format_nested_section( From 68e292ef0908d03f972b11bb25dfb6d69fb4a9a2 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 10:54:32 +0000 Subject: [PATCH 311/362] NVDATool: Moved format_nested_section func to utils.py --- site_scons/site_tools/NVDATool/manifests.py | 12 +----------- site_scons/site_tools/NVDATool/utils.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py index 9317419..f75bca3 100644 --- a/site_scons/site_tools/NVDATool/manifests.py +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -4,19 +4,9 @@ from collections.abc import Mapping from .typings import AddonInfo, BrailleTables, SymbolDictionaries, Strable +from .utils import format_nested_section -def format_nested_section( - section_name: str, - data: Mapping[str, Mapping[str, Strable]] -) -> str: - lines = [f"\n[{section_name}]"] - for item_name, inner_dict in data.items(): - lines.append(f"[[{item_name}]]") - for key, val in inner_dict.items(): - lines.append(f"{key} = {val}") - return "\n".join(lines) + "\n" - def generateManifest( source: str, diff --git a/site_scons/site_tools/NVDATool/utils.py b/site_scons/site_tools/NVDATool/utils.py index 326d394..c103770 100644 --- a/site_scons/site_tools/NVDATool/utils.py +++ b/site_scons/site_tools/NVDATool/utils.py @@ -1,3 +1,8 @@ +from collections.abc import Mapping + +from .typings import Strable + + def _(arg: str) -> str: """ @@ -5,3 +10,15 @@ def _(arg: str) -> str: Needed for recognizing strings for translation by Gettext. """ return arg + + +def format_nested_section( + section_name: str, + data: Mapping[str, Mapping[str, Strable]] +) -> str: + lines = [f"\n[{section_name}]"] + for item_name, inner_dict in data.items(): + lines.append(f"[[{item_name}]]") + for key, val in inner_dict.items(): + lines.append(f"{key} = {val}") + return "\n".join(lines) + "\n" From 3420405844a12b0ddcebbacabf9036c9b021a4d5 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 12:06:33 +0000 Subject: [PATCH 312/362] NVDATool: Update format_nested_section util Added an argument to limit the fields that will be added. Also, the value is now translated using the passed function. --- site_scons/site_tools/NVDATool/utils.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/site_scons/site_tools/NVDATool/utils.py b/site_scons/site_tools/NVDATool/utils.py index c103770..36bb3b3 100644 --- a/site_scons/site_tools/NVDATool/utils.py +++ b/site_scons/site_tools/NVDATool/utils.py @@ -1,4 +1,4 @@ -from collections.abc import Mapping +from collections.abc import Callable, Container, Mapping from .typings import Strable @@ -14,11 +14,15 @@ def _(arg: str) -> str: def format_nested_section( section_name: str, - data: Mapping[str, Mapping[str, Strable]] + data: Mapping[str, Mapping[str, Strable]], + include_only_keys: Container[str]|None = None, + _: Callable[[str], str] = _, ) -> str: lines = [f"\n[{section_name}]"] for item_name, inner_dict in data.items(): lines.append(f"[[{item_name}]]") for key, val in inner_dict.items(): - lines.append(f"{key} = {val}") + if include_only_keys and key not in include_only_keys: + continue + lines.append(f"{key} = {_(str(val))}") return "\n".join(lines) + "\n" From b989853491aaf5e8abd6dd3e3e93f56363582b08 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 12:11:43 +0000 Subject: [PATCH 313/362] NVDATool: Refactored generateTranslatedManifest Removed _format_section_only_with_displayName function This function has now been replaced by format_nested_section with fixed arguments via functools.partial. --- site_scons/site_tools/NVDATool/manifests.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py index f75bca3..53446ea 100644 --- a/site_scons/site_tools/NVDATool/manifests.py +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -1,9 +1,9 @@ import codecs import gettext -from collections.abc import Mapping +from functools import partial -from .typings import AddonInfo, BrailleTables, SymbolDictionaries, Strable +from .typings import AddonInfo, BrailleTables, SymbolDictionaries from .utils import format_nested_section @@ -50,13 +50,11 @@ def generateTranslatedManifest( manifest_template = f.read() manifest = manifest_template.format(**vars) - def _format_section_only_with_displayName(section_name: str, data: Mapping[str, Mapping[str, Strable]]) -> str: - lines = [f"\n[{section_name}]"] - for item, inner_dict in data.items(): - lines.append(f"[[{item}]]") - # Fetch display name only. - lines.append(f"displayName = {_(str(inner_dict['displayName']))}") - return "\n".join(lines) + "\n" + _format_section_only_with_displayName = partial( + format_nested_section, + include_only_keys = ("displayName",), + _ = _, + ) # Add additional manifest sections such as custom braile tables # Custom braille translation tables From b6c38dacc730de30f8401f0163278d7bc6779028 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 12:49:22 +0000 Subject: [PATCH 314/362] NVDATool: Update md2html func Replaced codecs.open with pathlib.Path.open --- site_scons/site_tools/NVDATool/docs.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index 6c4f607..dc354bf 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -1,6 +1,5 @@ import gettext -import codecs from pathlib import Path import markdown @@ -11,7 +10,7 @@ def md2html( source: str|Path, - dest: str, + dest: str|Path, *, localeDir: Path, loacleFileName: str, @@ -20,6 +19,8 @@ def md2html( ): if isinstance(source, str): source = Path(source) + if isinstance(dest, str): + dest = Path(dest) # Use extensions if defined. localeLang = source.parent.name @@ -38,7 +39,7 @@ def md2html( '[[!meta title="': "# ", '"]]': " #", } - with codecs.open(str(source), "r", "utf-8") as f: + with source.open("r") as f: mdText = f.read() for k, v in headerDic.items(): mdText = mdText.replace(k, v, 1) @@ -58,5 +59,5 @@ def md2html( "\n", ) ) - with codecs.open(dest, "w", "utf-8") as f: - f.write(docText) + with dest.open("w") as f: + f.write(docText) # type: ignore From 307361c4116c826b9218d69d88d0cd56f8dc39bb Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 14:38:27 +0000 Subject: [PATCH 315/362] SConstruct: Fixed moFile binding to mdFile Due to the mismatch of key types when adding and retrieving moFile from moByLang, they were not generated in the correct sequence. --- sconstruct | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sconstruct b/sconstruct index 8c3e82d..bac5725 100644 --- a/sconstruct +++ b/sconstruct @@ -81,20 +81,21 @@ if "channel" in env and env["channel"] is not None: addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir), excludePatterns=buildVars.excludedFiles) -langDirs: list[FS.Dir] = [d for d in env.Glob(localeDir/"*/")] +langDirs: list[FS.Dir] = [env.Dir(d) for d in env.Glob(localeDir/"*/") if d.isdir()] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated -moByLang: dict[FS.Dir, FS.File] = {} +moByLang: dict[str, FS.File] = {} for dir in langDirs: poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) - moFile = env.gettextMoFile(poFile) - moByLang[dir] = moFile - env.Depends(moFile, poFile) + moTarget = env.gettextMoFile(poFile) + moFile = env.File(moTarget[0]) + moByLang[dir.name] = moFile + env.Depends(moTarget, poFile) translatedManifest = env.NVDATranslatedManifest( dir.File("manifest.ini"), [moFile, "manifest-translated.ini.tpl"] ) env.Depends(translatedManifest, ["buildVars.py"]) - env.Depends(addon, [translatedManifest, moFile]) + env.Depends(addon, [translatedManifest, moTarget]) pythonFiles = expandGlobs(buildVars.pythonSources) for file in pythonFiles: @@ -115,7 +116,7 @@ if (readmeFile := Path("readme.md")).is_file(): for mdFile in env.Glob(docsDir/"*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. - lang = Path(str(mdFile)).absolute().parent.name + lang = mdFile.dir.name moFile = moByLang.get(lang) htmlFile = env.md2html(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) env.Depends(htmlFile, mdFile) From 604778e7119f445710dcfcf30cbb31866bc1cbb4 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sat, 2 Aug 2025 18:14:46 +0000 Subject: [PATCH 316/362] SConstruct, NVDATool: Updated md2html Now, instead of localeDir and localeFileName, and then specifying the language, you immediately get the .mo file. --- sconstruct | 2 +- site_scons/site_tools/NVDATool/__init__.py | 8 ++------ site_scons/site_tools/NVDATool/docs.py | 19 +++++++++++-------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/sconstruct b/sconstruct index bac5725..df8d74e 100644 --- a/sconstruct +++ b/sconstruct @@ -118,7 +118,7 @@ for mdFile in env.Glob(docsDir/"*/*.md"): # Thus, we find the moFile for this language and depend on it if it exists. lang = mdFile.dir.name moFile = moByLang.get(lang) - htmlFile = env.md2html(mdFile, localeDir=localeDir, localeFileName="nvda", mdExtensions=buildVars.markdownExtensions) + htmlFile = env.md2html(mdFile, moFile=moFile, mdExtensions=buildVars.markdownExtensions) env.Depends(htmlFile, mdFile) if moFile: env.Depends(htmlFile, moFile) diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 79d5b68..9367d19 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -16,8 +16,7 @@ The following environment variables are required to build the HTML: -- localeDir: str -- localeFileName: str +- moFile: str|Path|None - mdExtensions: list[str] - addon_info: .typings.AddonInfo @@ -85,16 +84,13 @@ def generate(env: Environment): src_siffix=".ini.tpl" ) - env.SetDefault(localeDir = Path("locale/")) - env.SetDefault(localeFileName = "messages") env.SetDefault(mdExtensions = {}) mdAction = env.Action( lambda target, source, env: md2html( source[0].path, target[0].path, - localeDir=env["localeDir"], - loacleFileName=env["localeFileName"], + moFile=env["moFile"].path if env["moFile"] else None, mdExtensions=env["mdExtensions"], addon_info=env["addon_info"], ) and None, diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index dc354bf..fa22d06 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -4,6 +4,7 @@ import markdown +from . import utils from .typings import AddonInfo @@ -12,8 +13,7 @@ def md2html( source: str|Path, dest: str|Path, *, - localeDir: Path, - loacleFileName: str, + moFile: str|Path|None, mdExtensions: list[str], addon_info: AddonInfo ): @@ -21,19 +21,22 @@ def md2html( source = Path(source) if isinstance(dest, str): dest = Path(dest) + if isinstance(moFile, str): + moFile = Path(moFile) # Use extensions if defined. localeLang = source.parent.name lang = localeLang.replace("_", "-") try: - _ = gettext.translation( - loacleFileName, - localedir=localeDir, - languages=[localeLang] - ).gettext - summary = _(addon_info["addon_summary"]) + if moFile is not None: + with moFile.open("rb") as f: + _ = gettext.GNUTranslations(f).gettext + else: + _ = utils._ except Exception: summary = addon_info["addon_summary"] + else: + summary = _(addon_info["addon_summary"]) title = f"{summary} {addon_info["addon_version"]}" headerDic = { '[[!meta title="': "# ", From 57d14fcab931f9dfa5c64c965e053f203a3534e5 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 3 Aug 2025 06:41:10 +0000 Subject: [PATCH 317/362] buildVars: Refactored definition of addon_info Use function-like init style, with keywords args --- buildVars.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/buildVars.py b/buildVars.py index b57a438..9843f38 100644 --- a/buildVars.py +++ b/buildVars.py @@ -12,40 +12,40 @@ # Add-on information variables -addon_info: AddonInfo = { +addon_info = AddonInfo( # add-on Name/identifier, internal for NVDA - "addon_name": "addonTemplate", + addon_name="addonTemplate", # Add-on summary/title, usually the user visible name of the add-on # Translators: Summary/title for this add-on # to be shown on installation and add-on information found in add-on store - "addon_summary": _("Add-on user visible name"), + addon_summary=_("Add-on user visible name"), # Add-on description # Translators: Long description to be shown for this add-on on add-on information from add-on store - "addon_description": _("""Description for the add-on. + addon_description=_("""Description for the add-on. It can span multiple lines."""), # version - "addon_version": "x.y", + addon_version="x.y", # Author(s) - "addon_author": "name ", + addon_author="name ", # URL for the add-on documentation support - "addon_url": None, + addon_url=None, # URL for the add-on repository where the source code can be found - "addon_sourceURL": None, + addon_sourceURL=None, # Documentation file name - "addon_docFileName": "readme.html", + addon_docFileName="readme.html", # Minimum NVDA version supported (e.g. "2019.3.0", minor version is optional) - "addon_minimumNVDAVersion": None, + addon_minimumNVDAVersion=None, # Last NVDA version supported/tested (e.g. "2024.4.0", ideally more recent than minimum version) - "addon_lastTestedNVDAVersion": None, + addon_lastTestedNVDAVersion=None, # Add-on update channel (default is None, denoting stable releases, # and for development releases, use "dev".) # Do not change unless you know what you are doing! - "addon_updateChannel": None, + addon_updateChannel=None, # Add-on license such as GPL 2 - "addon_license": None, + addon_license=None, # URL for the license document the ad-on is licensed under - "addon_licenseURL": None, -} + addon_licenseURL=None, +) # Define the python files that are the sources of your add-on. # You can either list every file (using ""/") as a path separator, From 3ccc1ebcfc2ad6694248aca30759514af34c0661 Mon Sep 17 00:00:00 2001 From: balaraz Date: Sun, 3 Aug 2025 07:49:14 +0000 Subject: [PATCH 318/362] NVDATool.md2html: Fixed title definition In target Python 3.11 does not support extended f-string --- site_scons/site_tools/NVDATool/docs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index fa22d06..d846e92 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -37,7 +37,8 @@ def md2html( summary = addon_info["addon_summary"] else: summary = _(addon_info["addon_summary"]) - title = f"{summary} {addon_info["addon_version"]}" + version = addon_info["addon_version"] + title = f"{summary} {version}" headerDic = { '[[!meta title="': "# ", '"]]': " #", From 1eef48a9f6b81340b6938c9bc0cbb3de49a2f66e Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 5 Aug 2025 13:58:09 +0000 Subject: [PATCH 319/362] NVDATool: Refactored md2html func --- site_scons/site_tools/NVDATool/docs.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index d846e92..55a1417 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -4,7 +4,6 @@ import markdown -from . import utils from .typings import AddonInfo @@ -24,21 +23,16 @@ def md2html( if isinstance(moFile, str): moFile = Path(moFile) - # Use extensions if defined. - localeLang = source.parent.name - lang = localeLang.replace("_", "-") try: - if moFile is not None: - with moFile.open("rb") as f: - _ = gettext.GNUTranslations(f).gettext - else: - _ = utils._ + with moFile.open("rb") as f: + _ = gettext.GNUTranslations(f).gettext except Exception: summary = addon_info["addon_summary"] else: summary = _(addon_info["addon_summary"]) version = addon_info["addon_version"] title = f"{summary} {version}" + lang = source.parent.name.replace("_", "-") headerDic = { '[[!meta title="': "# ", '"]]': " #", From 6919905e981a3b1cf79f4b75dfe5c2b379b6a20d Mon Sep 17 00:00:00 2001 From: balaraz Date: Tue, 5 Aug 2025 13:59:15 +0000 Subject: [PATCH 320/362] SConstruct: Fixed applying addon_info --- sconstruct | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sconstruct b/sconstruct index df8d74e..282b019 100644 --- a/sconstruct +++ b/sconstruct @@ -61,7 +61,6 @@ env.Append( addon_info=buildVars.addon_info, brailleTables=buildVars.brailleTables, symbolDictionaries=buildVars.symbolDictionaries, - **buildVars.addon_info ) if env["dev"]: @@ -69,13 +68,16 @@ if env["dev"]: versionTimestamp = date.today().strftime('%Y%m%d') version = f"{versionTimestamp}.0.0" - env["addon_version"] = version + env["addon_info"]["addon_version"] = version env["versionNumber"] = version env["channel"] = "dev" elif env["version"] is not None: - env["addon_version"] = env["version"] + env["addon_info"]["addon_version"] = env["version"] if "channel" in env and env["channel"] is not None: - env["addon_updateChannel"] = env["channel"] + env["addon_info"]["addon_updateChannel"] = env["channel"] + +# This is necessary for further use in formatting file names. +env.Append(**env["addon_info"]) addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") From d069b54b6af01c513409aab4caa140c5e0041f5c Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 5 Aug 2025 08:28:34 -0600 Subject: [PATCH 321/362] SConstruct, NVDA tool: remove unused imports --- sconstruct | 2 +- site_scons/site_tools/NVDATool/__init__.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sconstruct b/sconstruct index 282b019..481a7ac 100644 --- a/sconstruct +++ b/sconstruct @@ -14,7 +14,7 @@ from typing import Final # Linters aren't aware about them. # To avoid PyRight `reportUndefinedVariable` errors about them they are imported explicitly. # When using other Scons functions please add them to the line below. -from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environment, Builder, Copy +from SCons.Script import EnsurePythonVersion, Variables, BoolVariable, Environment, Copy # Imports for type hints from SCons.Node import FS diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 9367d19..5f40c2d 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -22,8 +22,6 @@ """ -from pathlib import Path - from SCons.Script import Environment, Builder from .addon import createAddonBundleFromPath From 7dba876e1f605cf03e5c4c7f411e5c5b509f5c78 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 5 Aug 2025 08:38:09 -0600 Subject: [PATCH 322/362] Site tools: spacing around 'or' operator, mention pathlib.Path --- site_scons/site_tools/NVDATool/__init__.py | 2 +- site_scons/site_tools/NVDATool/addon.py | 2 +- site_scons/site_tools/NVDATool/docs.py | 6 +++--- site_scons/site_tools/NVDATool/typings.py | 14 +++++++------- site_scons/site_tools/NVDATool/utils.py | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 5f40c2d..6b4a37c 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -16,7 +16,7 @@ The following environment variables are required to build the HTML: -- moFile: str|Path|None +- moFile: str | pathlib.Path | None - mdExtensions: list[str] - addon_info: .typings.AddonInfo diff --git a/site_scons/site_tools/NVDATool/addon.py b/site_scons/site_tools/NVDATool/addon.py index adc1424..42e8d0e 100644 --- a/site_scons/site_tools/NVDATool/addon.py +++ b/site_scons/site_tools/NVDATool/addon.py @@ -9,7 +9,7 @@ def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: return not any((path.match(pattern) for pattern in patterns)) -def createAddonBundleFromPath(path: str|Path, dest: str, excludePatterns: Iterable[str]): +def createAddonBundleFromPath(path: str | Path, dest: str, excludePatterns: Iterable[str]): """Creates a bundle from a directory that contains an addon manifest file.""" if isinstance(path, str): path = Path(path) diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index 55a1417..09cc27b 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -9,10 +9,10 @@ def md2html( - source: str|Path, - dest: str|Path, + source: str | Path, + dest: str | Path, *, - moFile: str|Path|None, + moFile: str | Path|None, mdExtensions: list[str], addon_info: AddonInfo ): diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py index e7b1791..927f97f 100644 --- a/site_scons/site_tools/NVDATool/typings.py +++ b/site_scons/site_tools/NVDATool/typings.py @@ -8,14 +8,14 @@ class AddonInfo(TypedDict): addon_description: str addon_version: str addon_author: str - addon_url: str|None - addon_sourceURL: str|None + addon_url: str | None + addon_sourceURL: str | None addon_docFileName: str - addon_minimumNVDAVersion: str|None - addon_lastTestedNVDAVersion: str|None - addon_updateChannel: str|None - addon_license: str|None - addon_licenseURL: str|None + addon_minimumNVDAVersion: str | None + addon_lastTestedNVDAVersion: str | None + addon_updateChannel: str | None + addon_license: str | None + addon_licenseURL: str | None class BrailleTableAttributes(TypedDict): diff --git a/site_scons/site_tools/NVDATool/utils.py b/site_scons/site_tools/NVDATool/utils.py index 36bb3b3..0cc833c 100644 --- a/site_scons/site_tools/NVDATool/utils.py +++ b/site_scons/site_tools/NVDATool/utils.py @@ -15,7 +15,7 @@ def _(arg: str) -> str: def format_nested_section( section_name: str, data: Mapping[str, Mapping[str, Strable]], - include_only_keys: Container[str]|None = None, + include_only_keys: Container[str] | None = None, _: Callable[[str], str] = _, ) -> str: lines = [f"\n[{section_name}]"] From 77abd3b5558f3f6f34224e1935cca88f4741364c Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 5 Aug 2025 08:55:51 -0600 Subject: [PATCH 323/362] Readme: updates including dependencies and removal of versionNumber CLI switch --- readme.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 0495029..5642769 100644 --- a/readme.md +++ b/readme.md @@ -47,9 +47,9 @@ In addition, this template includes configuration files for the following tools You need the following software to use this code for your NVDA add-on development and packaging: * a Python distribution (3.11 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.11 with 64-bit version planned. -* Scons - [Website](https://www.scons.org/) - version 4.8.1 or later. You can install it via PIP. +* Scons - [Website](https://www.scons.org/) - version 4.9.1 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). -* Markdown 3.7 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. +* Markdown 3.8 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. * Optional: additional tools such as linters and type checkers defined in pyproject.toml file. Note, that you may not need these tools in a local build environment, if you are using [Appveyor](https://appveyor.com/) or [GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions), to build and package your add-ons. @@ -141,8 +141,7 @@ Note: you must fill out this dictionary if at least one custom symbol dictionary 1. Open a command line, change to the folder that has the `sconstruct` file (usually the root of your add-on development folder) and run the `scons` command. The created add-on, if there were no errors, is placed in the current directory. 2. You can further customize variables in the `buildVars.py` file. 3. You can also customize version and update channel information from command line by passing the following switches when running scons: - * version: add-on version string. - * versionNumber: add-on version number of the form major.minor.patch (all integers) + * version: add-on version string of the form major.minor or major.minor.patch (all integers) * channel: update channel (do not use this switch unless you know what you are doing). * dev: suitable for development builds, names the add-on according to current date (yyyymmdd) and sets update channel to "dev". From 6c023a48d281be5509a983d90c02a8f682e4b324 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 11 Aug 2025 05:39:07 -0600 Subject: [PATCH 324/362] BuildVars: add 'changelog' manifest key to record latest changes for the add-on version being released/tagged --- buildVars.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/buildVars.py b/buildVars.py index 9843f38..c125fae 100644 --- a/buildVars.py +++ b/buildVars.py @@ -25,6 +25,10 @@ It can span multiple lines."""), # version addon_version="x.y", + # Brief changelog for this version + # Translators: what's new content for the add-on version to be shown in the add-on store + addon_changelog=_("""Changelog for the add-on version. +It can span multiple lines."""), # Author(s) addon_author="name ", # URL for the add-on documentation support From 2c2166d999777ac406f0ae67df592197fd26ce5e Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 11 Aug 2025 05:40:21 -0600 Subject: [PATCH 325/362] Manifest template: add 'chagelog' key --- manifest.ini.tpl | 1 + 1 file changed, 1 insertion(+) diff --git a/manifest.ini.tpl b/manifest.ini.tpl index d44355d..99144ec 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -4,6 +4,7 @@ description = """{addon_description}""" author = "{addon_author}" url = {addon_url} version = {addon_version} +changelog = {addon_changelog} docFileName = {addon_docFileName} minimumNVDAVersion = {addon_minimumNVDAVersion} lastTestedNVDAVersion = {addon_lastTestedNVDAVersion} From 1846beba5487ca149a3d45ff77d1cef1b05327d6 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 11 Aug 2025 06:43:27 -0600 Subject: [PATCH 326/362] Manifest template: add 'changelog' to translatable manifest template --- manifest-translated.ini.tpl | 1 + 1 file changed, 1 insertion(+) diff --git a/manifest-translated.ini.tpl b/manifest-translated.ini.tpl index c06aa84..9a841f6 100644 --- a/manifest-translated.ini.tpl +++ b/manifest-translated.ini.tpl @@ -1,2 +1,3 @@ summary = "{addon_summary}" description = """{addon_description}""" +changelog = {addon_changelog} From 75df0dc20cd56c8e84589c55b0e44d778951237b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 02:41:09 +0000 Subject: [PATCH 327/362] Bump actions/download-artifact from 4 to 5 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 1cf0f09..999a8c6 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -56,7 +56,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: download releases files - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 - name: Display structure of downloaded files run: ls -R - name: Calculate sha256 From bfe944a68f5fc8abcd71edf1b850d4b24d1f8f19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 03:10:13 +0000 Subject: [PATCH 328/362] Bump actions/checkout from 4 to 5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 1cf0f09..7a13794 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt @@ -54,7 +54,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: download releases files uses: actions/download-artifact@v4 - name: Display structure of downloaded files From b5c38cb51d191537b31847ae1dfd3c142a936c50 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 12 Aug 2025 10:21:19 -0600 Subject: [PATCH 329/362] Readme: document 'changelog' manifest key --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 5642769..bb6946f 100644 --- a/readme.md +++ b/readme.md @@ -92,6 +92,7 @@ An add-on manifest generated manually or via `buildVars.py` must include the fol * Summary (string): name as shown on NVDA's Add-on store. * Description (string): a short detailed description about the add-on. * Version (string), ideally number.number with an optional third number, denoting major.minor.patch. +* Changelog (string): changes between previous and current add-on releases. * Author (string and an email address): one or more add-on author contact information in the form "name ". * URL (string): a web address where the add-on information can be found such as add-on repository. * docFileName (string): name of the documentation file. From 2abc1de1d265eb766ca983e2cbcea565ce015d16 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 18 Aug 2025 07:31:40 -0600 Subject: [PATCH 330/362] Site_scons.NVDA tool: add type hint for add-on changelog key and declare it as localizable. Closes #64 --- site_scons/site_tools/NVDATool/manifests.py | 2 +- site_scons/site_tools/NVDATool/typings.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py index 53446ea..1e38348 100644 --- a/site_scons/site_tools/NVDATool/manifests.py +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -44,7 +44,7 @@ def generateTranslatedManifest( with open(mo, "rb") as f: _ = gettext.GNUTranslations(f).gettext vars: dict[str, str] = {} - for var in ("addon_summary", "addon_description"): + for var in ("addon_summary", "addon_description", "addon_changelog"): vars[var] = _(addon_info[var]) with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py index 927f97f..6b1b3f5 100644 --- a/site_scons/site_tools/NVDATool/typings.py +++ b/site_scons/site_tools/NVDATool/typings.py @@ -7,6 +7,7 @@ class AddonInfo(TypedDict): addon_summary: str addon_description: str addon_version: str + addon_changelog: str addon_author: str addon_url: str | None addon_sourceURL: str | None From 1cf8b8cd578efbd312fd42cd8e3291f0ae32d586 Mon Sep 17 00:00:00 2001 From: hwf1324 <1398969445@qq.com> Date: Tue, 19 Aug 2025 15:18:12 +0800 Subject: [PATCH 331/362] Delete fixed paths in upload jobs --- .github/workflows/build_addon.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index f6f9b00..aeefb75 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -62,14 +62,14 @@ jobs: - name: Calculate sha256 run: | echo -e "\nSHA256: " >> changelog.md - sha256sum packaged_addon/*.nvda-addon >> changelog.md + sha256sum *.nvda-addon >> changelog.md - name: Release uses: softprops/action-gh-release@v2 with: files: | - packaged_addon/*.nvda-addon - packaged_addon/*.pot + *.nvda-addon + *.pot body_path: changelog.md fail_on_unmatched_files: true prerelease: ${{ contains(github.ref, '-') }} From 2b9bf7bbc961557e155414b29d14b4e018250731 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 28 Aug 2025 21:47:40 -0600 Subject: [PATCH 332/362] Manifest: triple quote add-on changelog data --- manifest-translated.ini.tpl | 2 +- manifest.ini.tpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest-translated.ini.tpl b/manifest-translated.ini.tpl index 9a841f6..6df6d42 100644 --- a/manifest-translated.ini.tpl +++ b/manifest-translated.ini.tpl @@ -1,3 +1,3 @@ summary = "{addon_summary}" description = """{addon_description}""" -changelog = {addon_changelog} +changelog = """{addon_changelog}""" diff --git a/manifest.ini.tpl b/manifest.ini.tpl index 99144ec..2b7b0eb 100644 --- a/manifest.ini.tpl +++ b/manifest.ini.tpl @@ -4,7 +4,7 @@ description = """{addon_description}""" author = "{addon_author}" url = {addon_url} version = {addon_version} -changelog = {addon_changelog} +changelog = """{addon_changelog}""" docFileName = {addon_docFileName} minimumNVDAVersion = {addon_minimumNVDAVersion} lastTestedNVDAVersion = {addon_lastTestedNVDAVersion} From 29d9506da32b655573b40892b1859a456000bd90 Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Tue, 2 Sep 2025 13:24:39 +0200 Subject: [PATCH 333/362] NVDATool.docs - md2html: Fix encoding bug - Encoding still needs to be explicitly specified so that scons can be called on any plateform --- site_scons/site_tools/NVDATool/docs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index 09cc27b..abccd41 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -37,7 +37,7 @@ def md2html( '[[!meta title="': "# ", '"]]': " #", } - with source.open("r") as f: + with source.open("r", encoding="utf-8") as f: mdText = f.read() for k, v in headerDic.items(): mdText = mdText.replace(k, v, 1) @@ -57,5 +57,5 @@ def md2html( "\n", ) ) - with dest.open("w") as f: + with dest.open("w", encoding="utf-8") as f: f.write(docText) # type: ignore From fa4745ea875fb74f10c17d2af7816fa20603a276 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 19:16:14 +0000 Subject: [PATCH 334/362] Bump actions/setup-python from 5 to 6 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index aeefb75..dfe8073 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -22,7 +22,7 @@ jobs: - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.11 cache: 'pip' From f6fdfc1ab612e97e41b99918946de05e9a05c064 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Sat, 18 Oct 2025 14:39:05 -0600 Subject: [PATCH 335/362] Template readme: Python 3.11 -> 3.1 64-bit --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index bb6946f..6f989d1 100644 --- a/readme.md +++ b/readme.md @@ -46,7 +46,7 @@ In addition, this template includes configuration files for the following tools You need the following software to use this code for your NVDA add-on development and packaging: -* a Python distribution (3.11 or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. Please note that at present, preparing the NVDA source code requires the 32-bit version of Python 3.11 with 64-bit version planned. +* a Python distribution (3.13 64-bit or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. * Scons - [Website](https://www.scons.org/) - version 4.9.1 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). * Markdown 3.8 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. From d3f2ea6573c9d6418156567d15d09880d1942d3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:28:27 +0000 Subject: [PATCH 336/362] Bump actions/download-artifact from 5 to 6 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index dfe8073..f914eba 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -56,7 +56,7 @@ jobs: steps: - uses: actions/checkout@v5 - name: download releases files - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 - name: Display structure of downloaded files run: ls -R - name: Calculate sha256 From 8bc7e4a2f25fe56a96bbb59949b45afa40724f33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:50:29 +0000 Subject: [PATCH 337/362] Bump actions/upload-artifact from 4 to 5 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index dfe8073..30d049c 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -40,7 +40,7 @@ jobs: - name: building addon run: scons && scons pot - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v5 with: name: packaged_addon path: | From c81ad0ec17abf831671a45a3ae8c72f610bcd2f4 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Tue, 11 Nov 2025 06:51:14 -0700 Subject: [PATCH 338/362] Readme: SCons and Markdown dependency version updates, retire Appveyor (no more Appveyor mentions) --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 6f989d1..05e5f12 100644 --- a/readme.md +++ b/readme.md @@ -47,12 +47,12 @@ In addition, this template includes configuration files for the following tools You need the following software to use this code for your NVDA add-on development and packaging: * a Python distribution (3.13 64-bit or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. -* Scons - [Website](https://www.scons.org/) - version 4.9.1 or later. You can install it via PIP. +* Scons - [Website](https://www.scons.org/) - version 4.10.1 or later. You can install it via PIP. * GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). -* Markdown 3.8 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. +* Markdown 3.8.2 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. * Optional: additional tools such as linters and type checkers defined in pyproject.toml file. -Note, that you may not need these tools in a local build environment, if you are using [Appveyor](https://appveyor.com/) or [GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions), to build and package your add-ons. +Note: you may not need these tools in a local build environment; you can use [GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions) to build and package your add-ons. ## Usage From 8e0f88e9bd2b25df8c14bb7316da3cddf6b0733d Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Fri, 28 Nov 2025 01:00:23 +0100 Subject: [PATCH 339/362] Bump actions/checkout from 5 to 6 (#3) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_addon.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index ab0bba2..9e0fa64 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt @@ -54,7 +54,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: download releases files uses: actions/download-artifact@v6 - name: Display structure of downloaded files From 00c6b31aca1e3d5fd3ca8fb5c87174edc29eec0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Wed, 17 Dec 2025 00:56:10 +0100 Subject: [PATCH 340/362] Update precommit configuration (#4) --- .pre-commit-config.yaml | 92 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dd7a9d6..0c8f5c6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,87 @@ +# Copied from https://github.com/nvaccess/nvda +# https://pre-commit.ci/ +# Configuration for Continuous Integration service +ci: + # Pyright does not seem to work in pre-commit CI + skip: [pyright] + autoupdate_schedule: monthly + autoupdate_commit_msg: "Pre-commit auto-update" + autofix_commit_msg: "Pre-commit auto-fix" + submodules: true + +default_language_version: + python: python3.13 + repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 - hooks: - - id: check-ast - - id: check-case-conflict - - id: check-yaml +- repo: https://github.com/pre-commit-ci/pre-commit-ci-config + rev: v1.6.1 + hooks: + - id: check-pre-commit-ci-config + +- repo: meta + hooks: + # ensures that exclude directives apply to any file in the repository. + - id: check-useless-excludes + # ensures that the configured hooks apply to at least one file in the repository. + - id: check-hooks-apply + +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + # Prevents commits to certain branches + - id: no-commit-to-branch + args: ["--branch", "main", "master", ] + # Checks that large files have not been added. Default cut-off for "large" files is 500kb. + - id: check-added-large-files + # Checks python syntax + - id: check-ast + # Checks for filenames that will conflict on case insensitive filesystems (the majority of Windows filesystems, most of the time) + - id: check-case-conflict + # Checks for artifacts from resolving merge conflicts. + - id: check-merge-conflict + # Checks Python files for debug statements, such as python's breakpoint function, or those inserted by some IDEs. + - id: debug-statements + # Removes trailing whitespace. + - id: trailing-whitespace + types_or: [python, c, c++, batch, markdown, toml, yaml, powershell] + # Ensures all files end in 1 (and only 1) newline. + - id: end-of-file-fixer + types_or: [python, c, c++, batch, markdown, toml, yaml, powershell] + # Removes the UTF-8 BOM from files that have it. + # See https://github.com/nvaccess/nvda/blob/master/projectDocs/dev/codingStandards.md#encoding + - id: fix-byte-order-marker + types_or: [python, c, c++, batch, markdown, toml, yaml, powershell] + # Validates TOML files. + - id: check-toml + # Validates YAML files. + - id: check-yaml + # Ensures that links to lines in files under version control point to a particular commit. + - id: check-vcs-permalinks + # Avoids using reserved Windows filenames. + - id: check-illegal-windows-names +- repo: https://github.com/asottile/add-trailing-comma + rev: v3.2.0 + hooks: + # Ruff preserves indent/new-line formatting of function arguments, list items, and similar iterables, + # if a trailing comma is added. + # This adds a trailing comma to args/iterable items in case it was missed. + - id: add-trailing-comma + +- repo: https://github.com/astral-sh/ruff-pre-commit + # Matches Ruff version in pyproject. + rev: v0.12.7 + hooks: + - id: ruff + name: lint with ruff + args: [ --fix ] + - id: ruff-format + name: format with ruff + +- repo: local + hooks: + + - id: pyright + name: type check with pyright + entry: uv run pyright + language: system + types: [python] From 0273641b5f4a8fa03aef28fabfd656a176d2bc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 29 Dec 2025 09:23:57 +0100 Subject: [PATCH 341/362] Update pyproject (#5) This pull request introduces a new pyproject.toml configuration for the addonTemplate project, establishing modern Python project metadata, build settings, and development dependencies. It also updates and refines linting and static analysis configurations to improve code quality and development workflow. --- pyproject.toml | 54 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 97189ac..d43b0b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,46 @@ +[build-system] +requires = ["setuptools~=80.9", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "addonTemplate" +dynamic = ["version"] +description = "NVDA add-on template" +maintainers = [ + {name = "NV Access", email = "info@nvaccess.org"}, +] +requires-python = ">=3.13,<3.14" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: End Users/Desktop", + "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python :: 3", + "Topic :: Accessibility", +] +readme = "readme.md" +license = {file = "COPYING.TXT"} +dependencies = [ + # Build add-on + "scons==4.10.1", + "Markdown==3.10", + # Translations management + "requests==2.32.5", + "nh3==0.3.2", + "crowdin-api-client==1.24.1", + "lxml==6.0.2", + "mdx_truly_sane_lists==1.3", + "markdown-link-attr-modifier==0.2.1", + "mdx-gh-links==0.4", + # Lint + "uv==0.9.11", + "ruf==0.14.5", + "pre-commit==4.2.0", + "pyright[nodejs]==1.1.407", +] +[project.urls] +Repository = "https://github.com/nvaccess/addonTemplate" + [tool.ruff] line-length = 110 @@ -20,10 +63,13 @@ include = [ exclude = [ ".git", "__pycache__", + ".venv", + "buildVars.py", ] [tool.ruff.format] indent-style = "tab" +line-ending = "lf" [tool.ruff.lint.mccabe] max-complexity = 15 @@ -33,13 +79,16 @@ ignore = [ # indentation contains tabs "W191", ] +logger-objects = ["logHandler.log"] [tool.ruff.lint.per-file-ignores] -# sconstruct contains many inbuilt functions not recognised by the lint, +# sconscripts contains many inbuilt functions not recognised by the lint, # so ignore F821. "sconstruct" = ["F821"] [tool.pyright] +venvPath = ".venv" +venv = "." pythonPlatform = "Windows" typeCheckingMode = "strict" @@ -51,6 +100,7 @@ exclude = [ "sconstruct", ".git", "__pycache__", + ".venv", # When excluding concrete paths relative to a directory, # not matching multiple folders by name e.g. `__pycache__`, # paths are relative to the configuration file. @@ -59,6 +109,7 @@ exclude = [ # Tell pyright where to load python code from extraPaths = [ "./addon", + "../nvda/source", ] # General config @@ -120,7 +171,6 @@ reportPropertyTypeMismatch = true reportRedeclaration = true reportReturnType = true reportSelfClsParameterName = true -reportShadowedImports = true reportTypeCommentUsage = true reportTypedDictNotRequiredAccess = true reportUnboundVariable = true From 3ec67ac0443254d64c91e576be4f2dbcd36d2dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 30 Dec 2025 02:31:17 +0100 Subject: [PATCH 342/362] Fix branch args (#9) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0c8f5c6..207177d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: hooks: # Prevents commits to certain branches - id: no-commit-to-branch - args: ["--branch", "main", "master", ] + args: ["--branch", "main", "--branch", "master", ] # Checks that large files have not been added. Default cut-off for "large" files is 500kb. - id: check-added-large-files # Checks python syntax From c890dd091a1adc2462b1c94912f0755dd9ef49cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 30 Dec 2025 02:32:15 +0100 Subject: [PATCH 343/362] fixRuffInPyProject (#8) Fix ruff in pyproject Fix pyproject excluding siteScons from pyright --- pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d43b0b5..aa8752d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,10 +31,10 @@ dependencies = [ "lxml==6.0.2", "mdx_truly_sane_lists==1.3", "markdown-link-attr-modifier==0.2.1", - "mdx-gh-links==0.4", + "mdx-gh-links==0.4", # Lint "uv==0.9.11", - "ruf==0.14.5", + "ruff==0.14.5", "pre-commit==4.2.0", "pyright[nodejs]==1.1.407", ] @@ -101,6 +101,7 @@ exclude = [ ".git", "__pycache__", ".venv", + "site_scons", # When excluding concrete paths relative to a directory, # not matching multiple folders by name e.g. `__pycache__`, # paths are relative to the configuration file. From ce869354f990c90109ee5c039903fbb619a4b4bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 30 Dec 2025 04:57:30 +0100 Subject: [PATCH 344/362] Fixes using pre-commit (#10) --- .vscode/typings/__builtins__.pyi | 8 +- readme.md | 5 +- site_scons/site_tools/NVDATool/__init__.py | 25 +- site_scons/site_tools/NVDATool/addon.py | 1 - site_scons/site_tools/NVDATool/docs.py | 20 +- site_scons/site_tools/NVDATool/manifests.py | 34 +- site_scons/site_tools/NVDATool/typings.py | 13 +- site_scons/site_tools/NVDATool/utils.py | 1 - site_scons/site_tools/gettexttool/__init__.py | 6 +- uv.lock | 464 ++++++++++++++++++ 10 files changed, 519 insertions(+), 58 deletions(-) create mode 100644 uv.lock diff --git a/.vscode/typings/__builtins__.pyi b/.vscode/typings/__builtins__.pyi index 88febec..48cbde4 100644 --- a/.vscode/typings/__builtins__.pyi +++ b/.vscode/typings/__builtins__.pyi @@ -1,6 +1,2 @@ -def _(msg: str) -> str: - ... - - -def pgettext(context: str, message: str) -> str: - ... +def _(msg: str) -> str: ... +def pgettext(context: str, message: str) -> str: ... diff --git a/readme.md b/readme.md index 05e5f12..fb79067 100644 --- a/readme.md +++ b/readme.md @@ -36,7 +36,8 @@ In addition, this template includes configuration files for the following tools * Ruff (pyproject.toml/tool.ruff sections): a Python linter written in Rust. Sections starting with tool.ruff house configuration options for Ruff. * Configuration for VS Code. It requires NVDA's repo at the same level as the add-on folder containing your actual source files, with prepared source code (`scons source`). preparing the source code is a step in the instructions for building NVDA itself, see [The NVDA Repository](https://github.com/nvaccess/nvda) for details. * Place the .vscode in this repo within the addon folder, where your add-on source files (will) reside. The settings file within this folder assumes the NVDA repository is within the parent folder of this folder. If your addon folder is within the addonTemplate folder, then your NVDA repository folder needs to also be within the addonTemplate folder, or the source will not be found. - * Open the addon folder in VS Code. This should initialize VS Code with the correct settings and provide you with code completion and other VS Code features. + * Open the addon folder in VS Code. + This should initialize VS Code with the correct settings and provide you with code completion and other VS Code features. * Press `control+shift+m` after saving a file to search for problems. * Use arrow and tab keys for the autocompletion feature. * Press `control+shift+p` to open the commands palette and search for recommended extensions to install or check if they are installed. @@ -108,7 +109,7 @@ In addition, the following information must be filled out (not used in the manif ##### Custom add-on information -In addition to the core manifest data, custom add-on information can be specified. +In addition to the core manifest data, custom add-on information can be specified. ###### Braille translation tables diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index 6b4a37c..ff31eec 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -29,20 +29,22 @@ from .docs import md2html - def generate(env: Environment): env.SetDefault(excludePatterns=tuple()) addonAction = env.Action( lambda target, source, env: createAddonBundleFromPath( - source[0].abspath, target[0].abspath, env["excludePatterns"] - ) and None, + source[0].abspath, + target[0].abspath, + env["excludePatterns"], + ) + and None, lambda target, source, env: f"Generating Addon {target[0]}", ) env["BUILDERS"]["NVDAAddon"] = Builder( action=addonAction, suffix=".nvda-addon", - src_suffix="/" + src_suffix="/", ) env.SetDefault(brailleTables={}) @@ -55,13 +57,14 @@ def generate(env: Environment): addon_info=env["addon_info"], brailleTables=env["brailleTables"], symbolDictionaries=env["symbolDictionaries"], - ) and None, + ) + and None, lambda target, source, env: f"Generating manifest {target[0]}", ) env["BUILDERS"]["NVDAManifest"] = Builder( action=manifestAction, suffix=".ini", - src_siffix=".ini.tpl" + src_siffix=".ini.tpl", ) translatedManifestAction = env.Action( @@ -72,17 +75,18 @@ def generate(env: Environment): addon_info=env["addon_info"], brailleTables=env["brailleTables"], symbolDictionaries=env["symbolDictionaries"], - ) and None, + ) + and None, lambda target, source, env: f"Generating translated manifest {target[0]}", ) env["BUILDERS"]["NVDATranslatedManifest"] = Builder( action=translatedManifestAction, suffix=".ini", - src_siffix=".ini.tpl" + src_siffix=".ini.tpl", ) - env.SetDefault(mdExtensions = {}) + env.SetDefault(mdExtensions={}) mdAction = env.Action( lambda target, source, env: md2html( @@ -91,7 +95,8 @@ def generate(env: Environment): moFile=env["moFile"].path if env["moFile"] else None, mdExtensions=env["mdExtensions"], addon_info=env["addon_info"], - ) and None, + ) + and None, lambda target, source, env: f"Generating {target[0]}", ) env["BUILDERS"]["md2html"] = env.Builder( diff --git a/site_scons/site_tools/NVDATool/addon.py b/site_scons/site_tools/NVDATool/addon.py index 42e8d0e..7d67516 100644 --- a/site_scons/site_tools/NVDATool/addon.py +++ b/site_scons/site_tools/NVDATool/addon.py @@ -3,7 +3,6 @@ from pathlib import Path - def matchesNoPatterns(path: Path, patterns: Iterable[str]) -> bool: """Checks if the path, the first argument, does not match any of the patterns passed as the second argument.""" return not any((path.match(pattern) for pattern in patterns)) diff --git a/site_scons/site_tools/NVDATool/docs.py b/site_scons/site_tools/NVDATool/docs.py index abccd41..e1f80ad 100644 --- a/site_scons/site_tools/NVDATool/docs.py +++ b/site_scons/site_tools/NVDATool/docs.py @@ -1,4 +1,3 @@ - import gettext from pathlib import Path @@ -7,15 +6,14 @@ from .typings import AddonInfo - def md2html( - source: str | Path, - dest: str | Path, - *, - moFile: str | Path|None, - mdExtensions: list[str], - addon_info: AddonInfo - ): + source: str | Path, + dest: str | Path, + *, + moFile: str | Path | None, + mdExtensions: list[str], + addon_info: AddonInfo, +): if isinstance(source, str): source = Path(source) if isinstance(dest, str): @@ -55,7 +53,7 @@ def md2html( "\n", htmlText, "\n", - ) + ), ) with dest.open("w", encoding="utf-8") as f: - f.write(docText) # type: ignore + f.write(docText) # type: ignore diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py index 1e38348..a55785e 100644 --- a/site_scons/site_tools/NVDATool/manifests.py +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -1,4 +1,3 @@ - import codecs import gettext from functools import partial @@ -7,14 +6,13 @@ from .utils import format_nested_section - def generateManifest( - source: str, - dest: str, - addon_info: AddonInfo, - brailleTables: BrailleTables, - symbolDictionaries: SymbolDictionaries, - ): + source: str, + dest: str, + addon_info: AddonInfo, + brailleTables: BrailleTables, + symbolDictionaries: SymbolDictionaries, +): # Prepare the root manifest section with codecs.open(source, "r", "utf-8") as f: manifest_template = f.read() @@ -33,14 +31,14 @@ def generateManifest( def generateTranslatedManifest( - source: str, - dest: str, - *, - mo: str, - addon_info: AddonInfo, - brailleTables: BrailleTables, - symbolDictionaries: SymbolDictionaries, - ): + source: str, + dest: str, + *, + mo: str, + addon_info: AddonInfo, + brailleTables: BrailleTables, + symbolDictionaries: SymbolDictionaries, +): with open(mo, "rb") as f: _ = gettext.GNUTranslations(f).gettext vars: dict[str, str] = {} @@ -52,8 +50,8 @@ def generateTranslatedManifest( _format_section_only_with_displayName = partial( format_nested_section, - include_only_keys = ("displayName",), - _ = _, + include_only_keys=("displayName",), + _=_, ) # Add additional manifest sections such as custom braile tables diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py index 6b1b3f5..650a759 100644 --- a/site_scons/site_tools/NVDATool/typings.py +++ b/site_scons/site_tools/NVDATool/typings.py @@ -1,7 +1,6 @@ from typing import TypedDict, Protocol - class AddonInfo(TypedDict): addon_name: str addon_summary: str @@ -20,15 +19,15 @@ class AddonInfo(TypedDict): class BrailleTableAttributes(TypedDict): - displayName: str - contracted: bool - output: bool - input: bool + displayName: str + contracted: bool + output: bool + input: bool class SymbolDictionaryAttributes(TypedDict): - displayName: str - mandatory: bool + displayName: str + mandatory: bool BrailleTables = dict[str, BrailleTableAttributes] diff --git a/site_scons/site_tools/NVDATool/utils.py b/site_scons/site_tools/NVDATool/utils.py index 0cc833c..c900841 100644 --- a/site_scons/site_tools/NVDATool/utils.py +++ b/site_scons/site_tools/NVDATool/utils.py @@ -3,7 +3,6 @@ from .typings import Strable - def _(arg: str) -> str: """ A function that passes the string to it without doing anything to it. diff --git a/site_scons/site_tools/gettexttool/__init__.py b/site_scons/site_tools/gettexttool/__init__.py index 900f8dc..ff4697e 100644 --- a/site_scons/site_tools/gettexttool/__init__.py +++ b/site_scons/site_tools/gettexttool/__init__.py @@ -44,12 +44,14 @@ def generate(env): ) env["BUILDERS"]["gettextPotFile"] = env.Builder( - action=Action("xgettext " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), suffix=".pot" + action=Action("xgettext " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), + suffix=".pot", ) env["BUILDERS"]["gettextMergePotFile"] = env.Builder( action=Action( - "xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET" + "xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, + "Generating pot file $TARGET", ), suffix=".pot", ) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..e0def29 --- /dev/null +++ b/uv.lock @@ -0,0 +1,464 @@ +version = 1 +revision = 3 +requires-python = "==3.13.*" + +[[package]] +name = "addontemplate" +source = { editable = "." } +dependencies = [ + { name = "crowdin-api-client" }, + { name = "lxml" }, + { name = "markdown" }, + { name = "markdown-link-attr-modifier" }, + { name = "mdx-gh-links" }, + { name = "mdx-truly-sane-lists" }, + { name = "nh3" }, + { name = "pre-commit" }, + { name = "pyright", extra = ["nodejs"] }, + { name = "requests" }, + { name = "ruff" }, + { name = "scons" }, + { name = "uv" }, +] + +[package.metadata] +requires-dist = [ + { name = "crowdin-api-client", specifier = "==1.24.1" }, + { name = "lxml", specifier = "==6.0.2" }, + { name = "markdown", specifier = "==3.10" }, + { name = "markdown-link-attr-modifier", specifier = "==0.2.1" }, + { name = "mdx-gh-links", specifier = "==0.4" }, + { name = "mdx-truly-sane-lists", specifier = "==1.3" }, + { name = "nh3", specifier = "==0.3.2" }, + { name = "pre-commit", specifier = "==4.2.0" }, + { name = "pyright", extras = ["nodejs"], specifier = "==1.1.407" }, + { name = "requests", specifier = "==2.32.5" }, + { name = "ruff", specifier = "==0.14.5" }, + { name = "scons", specifier = "==4.10.1" }, + { name = "uv", specifier = "==0.9.11" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "crowdin-api-client" +version = "1.24.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deprecated" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/fc/ec5564928057aac9cae7e78ed324898b3134369b100bbb2b5c97ad1ad548/crowdin_api_client-1.24.1.tar.gz", hash = "sha256:d2a385c2b3f8e985d5bb084524ae14aef9045094fba0b2df1df82d9da97155b1", size = 70629, upload-time = "2025-08-26T13:20:34.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/74/118d8f5e592a1fe75b793346a599d57746b18b8875c31e956022b63ba173/crowdin_api_client-1.24.1-py3-none-any.whl", hash = "sha256:a07365a2a0d42830ee4eb188e3820603e1420421575637b1ddd8dffe1d2fe14c", size = 109654, upload-time = "2025-08-26T13:20:33.673Z" }, +] + +[[package]] +name = "deprecated" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/23/ce7a1126827cedeb958fc043d61745754464eb56c5937c35bbf2b8e26f34/filelock-3.20.1.tar.gz", hash = "sha256:b8360948b351b80f420878d8516519a2204b07aefcdcfd24912a5d33127f188c", size = 19476, upload-time = "2025-12-15T23:54:28.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/7f/a1a97644e39e7316d850784c642093c99df1290a460df4ede27659056834/filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a", size = 16666, upload-time = "2025-12-15T23:54:26.874Z" }, +] + +[[package]] +name = "identify" +version = "2.6.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, +] + +[[package]] +name = "markdown" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931, upload-time = "2025-11-03T19:51:15.007Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678, upload-time = "2025-11-03T19:51:13.887Z" }, +] + +[[package]] +name = "markdown-link-attr-modifier" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/30/d35aad054a27f119bff2408523d82c3f9a6d9936712c872f5b9fe817de5b/markdown_link_attr_modifier-0.2.1.tar.gz", hash = "sha256:18df49a9fe7b5c87dad50b75c2a2299ae40c65674f7b1263fb12455f5df7ac99", size = 18408, upload-time = "2023-04-13T16:00:12.798Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/82/9262a67313847fdcc6252a007f032924fe0c0b6d6b9ef0d0b1fa58952c72/markdown_link_attr_modifier-0.2.1-py3-none-any.whl", hash = "sha256:6b4415319648cbe6dfb7a54ca12fa69e61a27c86a09d15f2a9a559ace0aa87c5", size = 17146, upload-time = "2023-04-13T16:00:06.559Z" }, +] + +[[package]] +name = "mdx-gh-links" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/ea/bf1f721a8dc0ff83b426480f040ac68dbe3d7898b096c1277a5a4e3da0ec/mdx_gh_links-0.4.tar.gz", hash = "sha256:41d5aac2ab201425aa0a19373c4095b79e5e015fdacfe83c398199fe55ca3686", size = 5783, upload-time = "2023-12-22T19:54:02.136Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/c7/ccfe05ade98ba7a63f05d1b05b7508d9af743cbd1f1681aa0c9900a8cd40/mdx_gh_links-0.4-py3-none-any.whl", hash = "sha256:9057bca1fa5280bf1fcbf354381e46c9261cc32c2d5c0407801f8a910be5f099", size = 7166, upload-time = "2023-12-22T19:54:00.384Z" }, +] + +[[package]] +name = "mdx-truly-sane-lists" +version = "1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e6/27/16456314311abac2cedef4527679924e80ac4de19dd926699c1b261e0b9b/mdx_truly_sane_lists-1.3.tar.gz", hash = "sha256:b661022df7520a1e113af7c355c62216b384c867e4f59fb8ee7ad511e6e77f45", size = 5359, upload-time = "2022-07-19T13:42:45.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/9e/dcd1027f7fd193aed152e01c6651a197c36b858f2cd1425ad04cb31a34fc/mdx_truly_sane_lists-1.3-py3-none-any.whl", hash = "sha256:b9546a4c40ff8f1ab692f77cee4b6bfe8ddf9cccf23f0a24e71f3716fe290a37", size = 6071, upload-time = "2022-07-19T13:42:43.375Z" }, +] + +[[package]] +name = "nh3" +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/a5/34c26015d3a434409f4d2a1cd8821a06c05238703f49283ffeb937bef093/nh3-0.3.2.tar.gz", hash = "sha256:f394759a06df8b685a4ebfb1874fb67a9cbfd58c64fc5ed587a663c0e63ec376", size = 19288, upload-time = "2025-10-30T11:17:45.948Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/3e/f5a5cc2885c24be13e9b937441bd16a012ac34a657fe05e58927e8af8b7a/nh3-0.3.2-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7064ccf5ace75825bd7bf57859daaaf16ed28660c1c6b306b649a9eda4b54b1e", size = 1431980, upload-time = "2025-10-30T11:17:25.457Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f7/529a99324d7ef055de88b690858f4189379708abae92ace799365a797b7f/nh3-0.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8745454cdd28bbbc90861b80a0111a195b0e3961b9fa2e672be89eb199fa5d8", size = 820805, upload-time = "2025-10-30T11:17:26.98Z" }, + { url = "https://files.pythonhosted.org/packages/3d/62/19b7c50ccd1fa7d0764822d2cea8f2a320f2fd77474c7a1805cb22cf69b0/nh3-0.3.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72d67c25a84579f4a432c065e8b4274e53b7cf1df8f792cf846abfe2c3090866", size = 803527, upload-time = "2025-10-30T11:17:28.284Z" }, + { url = "https://files.pythonhosted.org/packages/4a/ca/f022273bab5440abff6302731a49410c5ef66b1a9502ba3fbb2df998d9ff/nh3-0.3.2-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:13398e676a14d6233f372c75f52d5ae74f98210172991f7a3142a736bd92b131", size = 1051674, upload-time = "2025-10-30T11:17:29.909Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f7/5728e3b32a11daf5bd21cf71d91c463f74305938bc3eb9e0ac1ce141646e/nh3-0.3.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03d617e5c8aa7331bd2659c654e021caf9bba704b109e7b2b28b039a00949fe5", size = 1004737, upload-time = "2025-10-30T11:17:31.205Z" }, + { url = "https://files.pythonhosted.org/packages/53/7f/f17e0dba0a99cee29e6cee6d4d52340ef9cb1f8a06946d3a01eb7ec2fb01/nh3-0.3.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f55c4d2d5a207e74eefe4d828067bbb01300e06e2a7436142f915c5928de07", size = 911745, upload-time = "2025-10-30T11:17:32.945Z" }, + { url = "https://files.pythonhosted.org/packages/42/0f/c76bf3dba22c73c38e9b1113b017cf163f7696f50e003404ec5ecdb1e8a6/nh3-0.3.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb18403f02b655a1bbe4e3a4696c2ae1d6ae8f5991f7cacb684b1ae27e6c9f7", size = 797184, upload-time = "2025-10-30T11:17:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/08/a1/73d8250f888fb0ddf1b119b139c382f8903d8bb0c5bd1f64afc7e38dad1d/nh3-0.3.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d66f41672eb4060cf87c037f760bdbc6847852ca9ef8e9c5a5da18f090abf87", size = 838556, upload-time = "2025-10-30T11:17:35.875Z" }, + { url = "https://files.pythonhosted.org/packages/d1/09/deb57f1fb656a7a5192497f4a287b0ade5a2ff6b5d5de4736d13ef6d2c1f/nh3-0.3.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f97f8b25cb2681d25e2338148159447e4d689aafdccfcf19e61ff7db3905768a", size = 1006695, upload-time = "2025-10-30T11:17:37.071Z" }, + { url = "https://files.pythonhosted.org/packages/b6/61/8f4d41c4ccdac30e4b1a4fa7be4b0f9914d8314a5058472f84c8e101a418/nh3-0.3.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:2ab70e8c6c7d2ce953d2a58102eefa90c2d0a5ed7aa40c7e29a487bc5e613131", size = 1075471, upload-time = "2025-10-30T11:17:38.225Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c6/966aec0cb4705e69f6c3580422c239205d5d4d0e50fac380b21e87b6cf1b/nh3-0.3.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:1710f3901cd6440ca92494ba2eb6dc260f829fa8d9196b659fa10de825610ce0", size = 1002439, upload-time = "2025-10-30T11:17:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c8/97a2d5f7a314cce2c5c49f30c6f161b7f3617960ade4bfc2fd1ee092cb20/nh3-0.3.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91e9b001101fb4500a2aafe3e7c92928d85242d38bf5ac0aba0b7480da0a4cd6", size = 987439, upload-time = "2025-10-30T11:17:40.81Z" }, + { url = "https://files.pythonhosted.org/packages/0d/95/2d6fc6461687d7a171f087995247dec33e8749a562bfadd85fb5dbf37a11/nh3-0.3.2-cp38-abi3-win32.whl", hash = "sha256:169db03df90da63286e0560ea0efa9b6f3b59844a9735514a1d47e6bb2c8c61b", size = 589826, upload-time = "2025-10-30T11:17:42.239Z" }, + { url = "https://files.pythonhosted.org/packages/64/9a/1a1c154f10a575d20dd634e5697805e589bbdb7673a0ad00e8da90044ba7/nh3-0.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:562da3dca7a17f9077593214a9781a94b8d76de4f158f8c895e62f09573945fe", size = 596406, upload-time = "2025-10-30T11:17:43.773Z" }, + { url = "https://files.pythonhosted.org/packages/9e/7e/a96255f63b7aef032cbee8fc4d6e37def72e3aaedc1f72759235e8f13cb1/nh3-0.3.2-cp38-abi3-win_arm64.whl", hash = "sha256:cf5964d54edd405e68583114a7cba929468bcd7db5e676ae38ee954de1cfc104", size = 584162, upload-time = "2025-10-30T11:17:44.96Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "nodejs-wheel-binaries" +version = "24.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/35/d806c2ca66072e36dc340ccdbeb2af7e4f1b5bcc33f1481f00ceed476708/nodejs_wheel_binaries-24.12.0.tar.gz", hash = "sha256:f1b50aa25375e264697dec04b232474906b997c2630c8f499f4caf3692938435", size = 8058, upload-time = "2025-12-11T21:12:26.856Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/3b/9d6f044319cd5b1e98f07c41e2465b58cadc1c9c04a74c891578f3be6cb5/nodejs_wheel_binaries-24.12.0-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:7564ddea0a87eff34e9b3ef71764cc2a476a8f09a5cccfddc4691148b0a47338", size = 55125859, upload-time = "2025-12-11T21:11:58.132Z" }, + { url = "https://files.pythonhosted.org/packages/48/a5/f5722bf15c014e2f476d7c76bce3d55c341d19122d8a5d86454db32a61a4/nodejs_wheel_binaries-24.12.0-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:8ff929c4669e64613ceb07f5bbd758d528c3563820c75d5de3249eb452c0c0ab", size = 55309035, upload-time = "2025-12-11T21:12:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/a9/61/68d39a6f1b5df67805969fd2829ba7e80696c9af19537856ec912050a2be/nodejs_wheel_binaries-24.12.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:6ebacefa8891bc456ad3655e6bce0af7e20ba08662f79d9109986faeb703fd6f", size = 59661017, upload-time = "2025-12-11T21:12:05.268Z" }, + { url = "https://files.pythonhosted.org/packages/16/a1/31aad16f55a5e44ca7ea62d1367fc69f4b6e1dba67f58a0a41d0ed854540/nodejs_wheel_binaries-24.12.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:3292649a03682ccbfa47f7b04d3e4240e8c46ef04dc941b708f20e4e6a764f75", size = 60159770, upload-time = "2025-12-11T21:12:08.696Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5e/b7c569aa1862690ca4d4daf3a64cafa1ea6ce667a9e3ae3918c56e127d9b/nodejs_wheel_binaries-24.12.0-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7fb83df312955ea355ba7f8cbd7055c477249a131d3cb43b60e4aeb8f8c730b1", size = 61653561, upload-time = "2025-12-11T21:12:12.575Z" }, + { url = "https://files.pythonhosted.org/packages/71/87/567f58d7ba69ff0208be849b37be0f2c2e99c69e49334edd45ff44f00043/nodejs_wheel_binaries-24.12.0-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:2473c819448fedd7b036dde236b09f3c8bbf39fbbd0c1068790a0498800f498b", size = 62238331, upload-time = "2025-12-11T21:12:16.143Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9d/c6492188ce8de90093c6755a4a63bb6b2b4efb17094cb4f9a9a49c73ed3b/nodejs_wheel_binaries-24.12.0-py2.py3-none-win_amd64.whl", hash = "sha256:2090d59f75a68079fabc9b86b14df8238b9aecb9577966dc142ce2a23a32e9bb", size = 41342076, upload-time = "2025-12-11T21:12:20.618Z" }, + { url = "https://files.pythonhosted.org/packages/df/af/cd3290a647df567645353feed451ef4feaf5844496ced69c4dcb84295ff4/nodejs_wheel_binaries-24.12.0-py2.py3-none-win_arm64.whl", hash = "sha256:d0c2273b667dd7e3f55e369c0085957b702144b1b04bfceb7ce2411e58333757", size = 39048104, upload-time = "2025-12-11T21:12:23.495Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.407" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/1b/0aa08ee42948b61745ac5b5b5ccaec4669e8884b53d31c8ec20b2fcd6b6f/pyright-1.1.407.tar.gz", hash = "sha256:099674dba5c10489832d4a4b2d302636152a9a42d317986c38474c76fe562262", size = 4122872, upload-time = "2025-10-24T23:17:15.145Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/93/b69052907d032b00c40cb656d21438ec00b3a471733de137a3f65a49a0a0/pyright-1.1.407-py3-none-any.whl", hash = "sha256:6dd419f54fcc13f03b52285796d65e639786373f433e243f8b94cf93a7444d21", size = 5997008, upload-time = "2025-10-24T23:17:13.159Z" }, +] + +[package.optional-dependencies] +nodejs = [ + { name = "nodejs-wheel-binaries" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/fa/fbb67a5780ae0f704876cb8ac92d6d76da41da4dc72b7ed3565ab18f2f52/ruff-0.14.5.tar.gz", hash = "sha256:8d3b48d7d8aad423d3137af7ab6c8b1e38e4de104800f0d596990f6ada1a9fc1", size = 5615944, upload-time = "2025-11-13T19:58:51.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/31/c07e9c535248d10836a94e4f4e8c5a31a1beed6f169b31405b227872d4f4/ruff-0.14.5-py3-none-linux_armv6l.whl", hash = "sha256:f3b8248123b586de44a8018bcc9fefe31d23dda57a34e6f0e1e53bd51fd63594", size = 13171630, upload-time = "2025-11-13T19:57:54.894Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/283c62516dca697cd604c2796d1487396b7a436b2f0ecc3fd412aca470e0/ruff-0.14.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f7a75236570318c7a30edd7f5491945f0169de738d945ca8784500b517163a72", size = 13413925, upload-time = "2025-11-13T19:57:59.181Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f3/aa319f4afc22cb6fcba2b9cdfc0f03bbf747e59ab7a8c5e90173857a1361/ruff-0.14.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6d146132d1ee115f8802356a2dc9a634dbf58184c51bff21f313e8cd1c74899a", size = 12574040, upload-time = "2025-11-13T19:58:02.056Z" }, + { url = "https://files.pythonhosted.org/packages/f9/7f/cb5845fcc7c7e88ed57f58670189fc2ff517fe2134c3821e77e29fd3b0c8/ruff-0.14.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2380596653dcd20b057794d55681571a257a42327da8894b93bbd6111aa801f", size = 13009755, upload-time = "2025-11-13T19:58:05.172Z" }, + { url = "https://files.pythonhosted.org/packages/21/d2/bcbedbb6bcb9253085981730687ddc0cc7b2e18e8dc13cf4453de905d7a0/ruff-0.14.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d1fa985a42b1f075a098fa1ab9d472b712bdb17ad87a8ec86e45e7fa6273e68", size = 12937641, upload-time = "2025-11-13T19:58:08.345Z" }, + { url = "https://files.pythonhosted.org/packages/a4/58/e25de28a572bdd60ffc6bb71fc7fd25a94ec6a076942e372437649cbb02a/ruff-0.14.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88f0770d42b7fa02bbefddde15d235ca3aa24e2f0137388cc15b2dcbb1f7c7a7", size = 13610854, upload-time = "2025-11-13T19:58:11.419Z" }, + { url = "https://files.pythonhosted.org/packages/7d/24/43bb3fd23ecee9861970978ea1a7a63e12a204d319248a7e8af539984280/ruff-0.14.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3676cb02b9061fee7294661071c4709fa21419ea9176087cb77e64410926eb78", size = 15061088, upload-time = "2025-11-13T19:58:14.551Z" }, + { url = "https://files.pythonhosted.org/packages/23/44/a022f288d61c2f8c8645b24c364b719aee293ffc7d633a2ca4d116b9c716/ruff-0.14.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b595bedf6bc9cab647c4a173a61acf4f1ac5f2b545203ba82f30fcb10b0318fb", size = 14734717, upload-time = "2025-11-13T19:58:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/58/81/5c6ba44de7e44c91f68073e0658109d8373b0590940efe5bd7753a2585a3/ruff-0.14.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f55382725ad0bdb2e8ee2babcbbfb16f124f5a59496a2f6a46f1d9d99d93e6e2", size = 14028812, upload-time = "2025-11-13T19:58:20.533Z" }, + { url = "https://files.pythonhosted.org/packages/ad/ef/41a8b60f8462cb320f68615b00299ebb12660097c952c600c762078420f8/ruff-0.14.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7497d19dce23976bdaca24345ae131a1d38dcfe1b0850ad8e9e6e4fa321a6e19", size = 13825656, upload-time = "2025-11-13T19:58:23.345Z" }, + { url = "https://files.pythonhosted.org/packages/7c/00/207e5de737fdb59b39eb1fac806904fe05681981b46d6a6db9468501062e/ruff-0.14.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:410e781f1122d6be4f446981dd479470af86537fb0b8857f27a6e872f65a38e4", size = 13959922, upload-time = "2025-11-13T19:58:26.537Z" }, + { url = "https://files.pythonhosted.org/packages/bc/7e/fa1f5c2776db4be405040293618846a2dece5c70b050874c2d1f10f24776/ruff-0.14.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c01be527ef4c91a6d55e53b337bfe2c0f82af024cc1a33c44792d6844e2331e1", size = 12932501, upload-time = "2025-11-13T19:58:29.822Z" }, + { url = "https://files.pythonhosted.org/packages/67/d8/d86bf784d693a764b59479a6bbdc9515ae42c340a5dc5ab1dabef847bfaa/ruff-0.14.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f66e9bb762e68d66e48550b59c74314168ebb46199886c5c5aa0b0fbcc81b151", size = 12927319, upload-time = "2025-11-13T19:58:32.923Z" }, + { url = "https://files.pythonhosted.org/packages/ac/de/ee0b304d450ae007ce0cb3e455fe24fbcaaedae4ebaad6c23831c6663651/ruff-0.14.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d93be8f1fa01022337f1f8f3bcaa7ffee2d0b03f00922c45c2207954f351f465", size = 13206209, upload-time = "2025-11-13T19:58:35.952Z" }, + { url = "https://files.pythonhosted.org/packages/33/aa/193ca7e3a92d74f17d9d5771a765965d2cf42c86e6f0fd95b13969115723/ruff-0.14.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c135d4b681f7401fe0e7312017e41aba9b3160861105726b76cfa14bc25aa367", size = 13953709, upload-time = "2025-11-13T19:58:39.002Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f1/7119e42aa1d3bf036ffc9478885c2e248812b7de9abea4eae89163d2929d/ruff-0.14.5-py3-none-win32.whl", hash = "sha256:c83642e6fccfb6dea8b785eb9f456800dcd6a63f362238af5fc0c83d027dd08b", size = 12925808, upload-time = "2025-11-13T19:58:42.779Z" }, + { url = "https://files.pythonhosted.org/packages/3b/9d/7c0a255d21e0912114784e4a96bf62af0618e2190cae468cd82b13625ad2/ruff-0.14.5-py3-none-win_amd64.whl", hash = "sha256:9d55d7af7166f143c94eae1db3312f9ea8f95a4defef1979ed516dbb38c27621", size = 14331546, upload-time = "2025-11-13T19:58:45.691Z" }, + { url = "https://files.pythonhosted.org/packages/e5/80/69756670caedcf3b9be597a6e12276a6cf6197076eb62aad0c608f8efce0/ruff-0.14.5-py3-none-win_arm64.whl", hash = "sha256:4b700459d4649e2594b31f20a9de33bc7c19976d4746d8d0798ad959621d64a4", size = 13433331, upload-time = "2025-11-13T19:58:48.434Z" }, +] + +[[package]] +name = "scons" +version = "4.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/c9/2f430bb39e4eccba32ce8008df4a3206df651276422204e177a09e12b30b/scons-4.10.1.tar.gz", hash = "sha256:99c0e94a42a2c1182fa6859b0be697953db07ba936ecc9817ae0d218ced20b15", size = 3258403, upload-time = "2025-11-16T22:43:39.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/bf/931fb9fbb87234c32b8b1b1c15fba23472a10777c12043336675633809a7/scons-4.10.1-py3-none-any.whl", hash = "sha256:bd9d1c52f908d874eba92a8c0c0a8dcf2ed9f3b88ab956d0fce1da479c4e7126", size = 4136069, upload-time = "2025-11-16T22:43:35.933Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" }, +] + +[[package]] +name = "uv" +version = "0.9.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/08/3bf76403ea7c22feef634849137fab10b28ab5ba5bbf08a53390763d5448/uv-0.9.11.tar.gz", hash = "sha256:605a7a57f508aabd029fc0c5ef5c60a556f8c50d32e194f1a300a9f4e87f18d4", size = 3744387, upload-time = "2025-11-20T23:20:00.95Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/26/8f917e9faddd9cb49abcbc8c7dac5343b0f61d04c6ac36873d2a324fee1a/uv-0.9.11-py3-none-linux_armv6l.whl", hash = "sha256:803f85cf25ab7f1fca10fe2e40a1b9f5b1d48efc25efd6651ba3c9668db6a19e", size = 20787588, upload-time = "2025-11-20T23:18:53.738Z" }, + { url = "https://files.pythonhosted.org/packages/f5/1f/eafd39c719ddee19fc25884f68c1a7e736c0fca63c1cbef925caf8ebd739/uv-0.9.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6a31b0bd4eaec59bf97816aefbcd75cae4fcc8875c4b19ef1846b7bff3d67c70", size = 19922144, upload-time = "2025-11-20T23:18:57.569Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f3/6b9fac39e5b65fa47dba872dcf171f1470490cd645343e8334f20f73885b/uv-0.9.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48548a23fb5a103b8955dfafff7d79d21112b8e25ce5ff25e3468dc541b20e83", size = 18380643, upload-time = "2025-11-20T23:19:01.02Z" }, + { url = "https://files.pythonhosted.org/packages/d6/9a/d4080e95950a4fc6fdf20d67b9a43ffb8e3d6d6b7c8dda460ae73ddbecd9/uv-0.9.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:cb680948e678590b5960744af2ecea6f2c0307dbb74ac44daf5c00e84ad8c09f", size = 20310262, upload-time = "2025-11-20T23:19:04.914Z" }, + { url = "https://files.pythonhosted.org/packages/6d/b4/86d9c881bd6accf2b766f7193b50e9d5815f2b34806191d90ea24967965e/uv-0.9.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9ef1982295e5aaf909a9668d6fb6abfc5089666c699f585a36f3a67f1a22916a", size = 20392988, upload-time = "2025-11-20T23:19:08.258Z" }, + { url = "https://files.pythonhosted.org/packages/a3/1d/6a227b7ca1829442c1419ba1db856d176b6e0861f9bf9355a8790a5d02b5/uv-0.9.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92ff773aa4193148019533c55382c2f9c661824bbf0c2e03f12aeefc800ede57", size = 21394892, upload-time = "2025-11-20T23:19:12.626Z" }, + { url = "https://files.pythonhosted.org/packages/5a/8f/df45b8409923121de8c4081c9d6d8ba3273eaa450645e1e542d83179c7b5/uv-0.9.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:70137a46675bbecf3a8b43d292a61767f1b944156af3d0f8d5986292bd86f6cf", size = 22987735, upload-time = "2025-11-20T23:19:16.27Z" }, + { url = "https://files.pythonhosted.org/packages/89/51/bbf3248a619c9f502d310a11362da5ed72c312d354fb8f9667c5aa3be9dd/uv-0.9.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5af9117bab6c4b3a1cacb0cddfb3cd540d0adfb13c7b8a9a318873cf2d07e52", size = 22617321, upload-time = "2025-11-20T23:19:20.1Z" }, + { url = "https://files.pythonhosted.org/packages/3f/cd/a158ec989c5433dc86ebd9fea800f2aed24255b84ab65b6d7407251e5e31/uv-0.9.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8cc86940d9b3a425575f25dc45247be2fb31f7fed7bf3394ae9daadd466e5b80", size = 21615712, upload-time = "2025-11-20T23:19:23.71Z" }, + { url = "https://files.pythonhosted.org/packages/73/da/2597becbc0fcbb59608d38fda5db79969e76dedf5b072f0e8564c8f0628b/uv-0.9.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e97906ca1b90dac91c23af20e282e2e37c8eb80c3721898733928a295f2defda", size = 21661022, upload-time = "2025-11-20T23:19:27.385Z" }, + { url = "https://files.pythonhosted.org/packages/52/66/9b8f3b3529b23c2a6f5b9612da70ea53117935ec999757b4f1d640f63d63/uv-0.9.11-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:d901269e1db72abc974ba61d37be6e56532e104922329e0b553d9df07ba224be", size = 20440548, upload-time = "2025-11-20T23:19:31.051Z" }, + { url = "https://files.pythonhosted.org/packages/72/b2/683afdb83e96dd966eb7cf3688af56a1b826c8bc1e8182fb10ec35b3e391/uv-0.9.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:8abfb7d4b136de3e92dd239ea9a51d4b7bbb970dc1b33bec84d08facf82b9a6e", size = 21493758, upload-time = "2025-11-20T23:19:34.688Z" }, + { url = "https://files.pythonhosted.org/packages/f4/00/99848bc9834aab104fa74aa1a60b1ca478dee824d2e4aacb15af85673572/uv-0.9.11-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:1f8afc13b3b94bce1e72514c598d41623387b2b61b68d7dbce9a01a0d8874860", size = 20332324, upload-time = "2025-11-20T23:19:38.376Z" }, + { url = "https://files.pythonhosted.org/packages/6c/94/8cfd1bb1cc5d768cb334f976ba2686c6327e4ac91c16b8469b284956d4d9/uv-0.9.11-py3-none-musllinux_1_1_i686.whl", hash = "sha256:7d414cfa410f1850a244d87255f98d06ca61cc13d82f6413c4f03e9e0c9effc7", size = 20845062, upload-time = "2025-11-20T23:19:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/a0/42/43f66bfc621464dabe9cfe3cbf69cddc36464da56ab786c94fc9ccf99cc7/uv-0.9.11-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:edc14143d0ba086a7da4b737a77746bb36bc00e3d26466f180ea99e3bf795171", size = 21857559, upload-time = "2025-11-20T23:19:46.026Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4d/bfd41bf087522601c724d712c3727aeb62f51b1f67c4ab86a078c3947525/uv-0.9.11-py3-none-win32.whl", hash = "sha256:af5fd91eecaa04b4799f553c726307200f45da844d5c7c5880d64db4debdd5dc", size = 19639246, upload-time = "2025-11-20T23:19:50.254Z" }, + { url = "https://files.pythonhosted.org/packages/2c/2f/d51c02627de68a7ca5b82f0a5d61d753beee3fe696366d1a1c5d5e40cd58/uv-0.9.11-py3-none-win_amd64.whl", hash = "sha256:c65a024ad98547e32168f3a52360fe73ff39cd609a8fb9dd2509aac91483cfc8", size = 21626822, upload-time = "2025-11-20T23:19:54.424Z" }, + { url = "https://files.pythonhosted.org/packages/af/d8/e07e866ee328d3c9f27a6d57a018d8330f47be95ef4654a178779c968a66/uv-0.9.11-py3-none-win_arm64.whl", hash = "sha256:4907a696c745703542ed2559bdf5380b92c8b1d4bf290ebfed45bf9a2a2c6690", size = 20046856, upload-time = "2025-11-20T23:19:58.517Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.35.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, +] + +[[package]] +name = "wrapt" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/fe/41af4c46b5e498c90fc87981ab2972fbd9f0bccda597adb99d3d3441b94b/wrapt-2.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:47b0f8bafe90f7736151f61482c583c86b0693d80f075a58701dd1549b0010a9", size = 78132, upload-time = "2025-11-07T00:44:04.628Z" }, + { url = "https://files.pythonhosted.org/packages/1c/92/d68895a984a5ebbbfb175512b0c0aad872354a4a2484fbd5552e9f275316/wrapt-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cbeb0971e13b4bd81d34169ed57a6dda017328d1a22b62fda45e1d21dd06148f", size = 61211, upload-time = "2025-11-07T00:44:05.626Z" }, + { url = "https://files.pythonhosted.org/packages/e8/26/ba83dc5ae7cf5aa2b02364a3d9cf74374b86169906a1f3ade9a2d03cf21c/wrapt-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb7cffe572ad0a141a7886a1d2efa5bef0bf7fe021deeea76b3ab334d2c38218", size = 61689, upload-time = "2025-11-07T00:44:06.719Z" }, + { url = "https://files.pythonhosted.org/packages/cf/67/d7a7c276d874e5d26738c22444d466a3a64ed541f6ef35f740dbd865bab4/wrapt-2.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8d60527d1ecfc131426b10d93ab5d53e08a09c5fa0175f6b21b3252080c70a9", size = 121502, upload-time = "2025-11-07T00:44:09.557Z" }, + { url = "https://files.pythonhosted.org/packages/0f/6b/806dbf6dd9579556aab22fc92908a876636e250f063f71548a8660382184/wrapt-2.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c654eafb01afac55246053d67a4b9a984a3567c3808bb7df2f8de1c1caba2e1c", size = 123110, upload-time = "2025-11-07T00:44:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/e5/08/cdbb965fbe4c02c5233d185d070cabed2ecc1f1e47662854f95d77613f57/wrapt-2.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:98d873ed6c8b4ee2418f7afce666751854d6d03e3c0ec2a399bb039cd2ae89db", size = 117434, upload-time = "2025-11-07T00:44:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/6aae2ce39db4cb5216302fa2e9577ad74424dfbe315bd6669725569e048c/wrapt-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9e850f5b7fc67af856ff054c71690d54fa940c3ef74209ad9f935b4f66a0233", size = 121533, upload-time = "2025-11-07T00:44:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/565abf57559fbe0a9155c29879ff43ce8bd28d2ca61033a3a3dd67b70794/wrapt-2.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e505629359cb5f751e16e30cf3f91a1d3ddb4552480c205947da415d597f7ac2", size = 116324, upload-time = "2025-11-07T00:44:13.28Z" }, + { url = "https://files.pythonhosted.org/packages/e1/e0/53ff5e76587822ee33e560ad55876d858e384158272cd9947abdd4ad42ca/wrapt-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2879af909312d0baf35f08edeea918ee3af7ab57c37fe47cb6a373c9f2749c7b", size = 120627, upload-time = "2025-11-07T00:44:14.431Z" }, + { url = "https://files.pythonhosted.org/packages/7c/7b/38df30fd629fbd7612c407643c63e80e1c60bcc982e30ceeae163a9800e7/wrapt-2.0.1-cp313-cp313-win32.whl", hash = "sha256:d67956c676be5a24102c7407a71f4126d30de2a569a1c7871c9f3cabc94225d7", size = 58252, upload-time = "2025-11-07T00:44:17.814Z" }, + { url = "https://files.pythonhosted.org/packages/85/64/d3954e836ea67c4d3ad5285e5c8fd9d362fd0a189a2db622df457b0f4f6a/wrapt-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9ca66b38dd642bf90c59b6738af8070747b610115a39af2498535f62b5cdc1c3", size = 60500, upload-time = "2025-11-07T00:44:15.561Z" }, + { url = "https://files.pythonhosted.org/packages/89/4e/3c8b99ac93527cfab7f116089db120fef16aac96e5f6cdb724ddf286086d/wrapt-2.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:5a4939eae35db6b6cec8e7aa0e833dcca0acad8231672c26c2a9ab7a0f8ac9c8", size = 58993, upload-time = "2025-11-07T00:44:16.65Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f4/eff2b7d711cae20d220780b9300faa05558660afb93f2ff5db61fe725b9a/wrapt-2.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a52f93d95c8d38fed0669da2ebdb0b0376e895d84596a976c15a9eb45e3eccb3", size = 82028, upload-time = "2025-11-07T00:44:18.944Z" }, + { url = "https://files.pythonhosted.org/packages/0c/67/cb945563f66fd0f61a999339460d950f4735c69f18f0a87ca586319b1778/wrapt-2.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e54bbf554ee29fcceee24fa41c4d091398b911da6e7f5d7bffda963c9aed2e1", size = 62949, upload-time = "2025-11-07T00:44:20.074Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ca/f63e177f0bbe1e5cf5e8d9b74a286537cd709724384ff20860f8f6065904/wrapt-2.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:908f8c6c71557f4deaa280f55d0728c3bca0960e8c3dd5ceeeafb3c19942719d", size = 63681, upload-time = "2025-11-07T00:44:21.345Z" }, + { url = "https://files.pythonhosted.org/packages/39/a1/1b88fcd21fd835dca48b556daef750952e917a2794fa20c025489e2e1f0f/wrapt-2.0.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e2f84e9af2060e3904a32cea9bb6db23ce3f91cfd90c6b426757cf7cc01c45c7", size = 152696, upload-time = "2025-11-07T00:44:24.318Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/d9185500c1960d9f5f77b9c0b890b7fc62282b53af7ad1b6bd779157f714/wrapt-2.0.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3612dc06b436968dfb9142c62e5dfa9eb5924f91120b3c8ff501ad878f90eb3", size = 158859, upload-time = "2025-11-07T00:44:25.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/60/5d796ed0f481ec003220c7878a1d6894652efe089853a208ea0838c13086/wrapt-2.0.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d2d947d266d99a1477cd005b23cbd09465276e302515e122df56bb9511aca1b", size = 146068, upload-time = "2025-11-07T00:44:22.81Z" }, + { url = "https://files.pythonhosted.org/packages/04/f8/75282dd72f102ddbfba137e1e15ecba47b40acff32c08ae97edbf53f469e/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7d539241e87b650cbc4c3ac9f32c8d1ac8a54e510f6dca3f6ab60dcfd48c9b10", size = 155724, upload-time = "2025-11-07T00:44:26.634Z" }, + { url = "https://files.pythonhosted.org/packages/5a/27/fe39c51d1b344caebb4a6a9372157bdb8d25b194b3561b52c8ffc40ac7d1/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4811e15d88ee62dbf5c77f2c3ff3932b1e3ac92323ba3912f51fc4016ce81ecf", size = 144413, upload-time = "2025-11-07T00:44:27.939Z" }, + { url = "https://files.pythonhosted.org/packages/83/2b/9f6b643fe39d4505c7bf926d7c2595b7cb4b607c8c6b500e56c6b36ac238/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c1c91405fcf1d501fa5d55df21e58ea49e6b879ae829f1039faaf7e5e509b41e", size = 150325, upload-time = "2025-11-07T00:44:29.29Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/20ffcf2558596a7f58a2e69c89597128781f0b88e124bf5a4cadc05b8139/wrapt-2.0.1-cp313-cp313t-win32.whl", hash = "sha256:e76e3f91f864e89db8b8d2a8311d57df93f01ad6bb1e9b9976d1f2e83e18315c", size = 59943, upload-time = "2025-11-07T00:44:33.211Z" }, + { url = "https://files.pythonhosted.org/packages/87/6a/0e56111cbb3320151eed5d3821ee1373be13e05b376ea0870711f18810c3/wrapt-2.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:83ce30937f0ba0d28818807b303a412440c4b63e39d3d8fc036a94764b728c92", size = 63240, upload-time = "2025-11-07T00:44:30.935Z" }, + { url = "https://files.pythonhosted.org/packages/1d/54/5ab4c53ea1f7f7e5c3e7c1095db92932cc32fd62359d285486d00c2884c3/wrapt-2.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:4b55cacc57e1dc2d0991dbe74c6419ffd415fb66474a02335cb10efd1aa3f84f", size = 60416, upload-time = "2025-11-07T00:44:32.002Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, +] From 7b7b8b15f95580081e96bfab2b6285b97723e61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 30 Dec 2025 05:29:18 +0100 Subject: [PATCH 345/362] Add a note encouraging to use pre-commit.ci (#11) --- readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readme.md b/readme.md index fb79067..9ad847a 100644 --- a/readme.md +++ b/readme.md @@ -43,6 +43,15 @@ In addition, this template includes configuration files for the following tools * Press `control+shift+p` to open the commands palette and search for recommended extensions to install or check if they are installed. * Pyright (pyproject.toml/tool.pyright sections): a Python static type checker. Sections starting with tool.pyright house configuration options for Pyright. +## Automatic checks on GitHub + +### Pre-commit + +It's recommended to install pre-commit.ci [pre-commit](https://pre-commit.ci) on personal GitHub accounts. +Then, you can choose if pre-commit will be used in all or just in selected repos. + +Setting up pre-commit.ci for each add-on using the add-on template will help you maintain a consistent code style in your add-ons. + ## Requirements You need the following software to use this code for your NVDA add-on development and packaging: From c6f50e9544d65b5d2f3d4cd149def616f0323ca8 Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Thu, 8 Jan 2026 05:40:32 +0100 Subject: [PATCH 346/362] Bump actions/download-artifact from 6 to 7 and bump actions/upload-artifact from 5 to 6 (#12) --- .github/workflows/build_addon.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 9e0fa64..c6aa8cb 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -40,7 +40,7 @@ jobs: - name: building addon run: scons && scons pot - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v6 with: name: packaged_addon path: | @@ -56,7 +56,7 @@ jobs: steps: - uses: actions/checkout@v6 - name: download releases files - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 - name: Display structure of downloaded files run: ls -R - name: Calculate sha256 From a4f9291de0e3a862c5a4ec989a388c8860aa0ae9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:18:15 +1100 Subject: [PATCH 347/362] Bump actions/download-artifact from 7 to 8 (#17) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index c6aa8cb..fe40e81 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -56,7 +56,7 @@ jobs: steps: - uses: actions/checkout@v6 - name: download releases files - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 - name: Display structure of downloaded files run: ls -R - name: Calculate sha256 From 20c3919c1e6e79103f9ef6c535da6a03a45c65cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:18:25 +1100 Subject: [PATCH 348/362] Bump actions/upload-artifact from 6 to 7 (#16) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index fe40e81..63a6f1d 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -40,7 +40,7 @@ jobs: - name: building addon run: scons && scons pot - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 with: name: packaged_addon path: | From 945487a235953b5d888e17f1f2a4f461d4151a24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:22:54 +1100 Subject: [PATCH 349/362] Bump the uv group across 1 directory with 3 updates (#18) Bumps the uv group with 3 updates in the / directory: [filelock](https://github.com/tox-dev/py-filelock), [urllib3](https://github.com/urllib3/urllib3) and [virtualenv](https://github.com/pypa/virtualenv). Updates `filelock` from 3.20.1 to 3.20.3 - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.20.1...3.20.3) Updates `urllib3` from 2.6.2 to 2.6.3 - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.6.2...2.6.3) Updates `virtualenv` from 20.35.4 to 20.36.1 - [Release notes](https://github.com/pypa/virtualenv/releases) - [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst) - [Commits](https://github.com/pypa/virtualenv/compare/20.35.4...20.36.1) --- updated-dependencies: - dependency-name: filelock dependency-version: 3.20.3 dependency-type: indirect dependency-group: uv - dependency-name: urllib3 dependency-version: 2.6.3 dependency-type: indirect dependency-group: uv - dependency-name: virtualenv dependency-version: 20.36.1 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/uv.lock b/uv.lock index e0def29..460a161 100644 --- a/uv.lock +++ b/uv.lock @@ -117,11 +117,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.20.1" +version = "3.20.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/23/ce7a1126827cedeb958fc043d61745754464eb56c5937c35bbf2b8e26f34/filelock-3.20.1.tar.gz", hash = "sha256:b8360948b351b80f420878d8516519a2204b07aefcdcfd24912a5d33127f188c", size = 19476, upload-time = "2025-12-15T23:54:28.027Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/7f/a1a97644e39e7316d850784c642093c99df1290a460df4ede27659056834/filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a", size = 16666, upload-time = "2025-12-15T23:54:26.874Z" }, + { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, ] [[package]] @@ -383,11 +383,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.2" +version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] [[package]] @@ -418,16 +418,16 @@ wheels = [ [[package]] name = "virtualenv" -version = "20.35.4" +version = "20.36.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, + { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, ] [[package]] From 3ac4b6f32d4d00e3974b143442453a18f25b3909 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 2 Mar 2026 16:46:55 -0700 Subject: [PATCH 350/362] Add-on template: add support for custom speech pronunciation dictionaries (NVDA 2026.2) (#19) Closes #15 This pull request add support for building custom speech pronunciation dictionaries via the add-on template. Changes made: Adds "speechDictionraies" sectoin to buildVars Adds speech dictionaries manifest key type and generation rules (borrowing custom symbol dictionaries) --- buildVars.py | 11 ++++++++++- readme.md | 13 +++++++++++++ sconstruct | 1 + site_scons/site_tools/NVDATool/__init__.py | 4 ++++ site_scons/site_tools/NVDATool/manifests.py | 12 +++++++++++- site_scons/site_tools/NVDATool/typings.py | 6 ++++++ 6 files changed, 45 insertions(+), 2 deletions(-) diff --git a/buildVars.py b/buildVars.py index c125fae..decefe4 100644 --- a/buildVars.py +++ b/buildVars.py @@ -99,5 +99,14 @@ # Each key is the name of the dictionary, # with keys inside recording the following attributes: # displayName (name of the speech dictionary shown to users and translatable), -# mandatory (True when always enabled, False when not. +# mandatory (True when always enabled, False when not). symbolDictionaries: SymbolDictionaries = {} + +# Custom speech dictionaries (distinct from symbol dictionaries above) +# Speech dictionary files reside in the speechDicts folder and are named `name.dic`. +# If your add-on includes custom speech (pronunciation) dictionaries (most will not), fill out this dictionary. +# Each key is the name of the dictionary, +# with keys inside recording the following attributes: +# displayName (name of the speech dictionary shown to users and translatable), +# mandatory (True when always enabled, False when not). +speechDictionaries: SpeechDictionaries = {} diff --git a/readme.md b/readme.md index 9ad847a..117eb2c 100644 --- a/readme.md +++ b/readme.md @@ -142,6 +142,19 @@ Information on custom symbol dictionaries must be specified in buildVars under ` Note: you must fill out this dictionary if at least one custom symbol dictionary is included in the add-on. If not, leave the dictionary empty. +###### Speech pronunciation dictionaries + +Information on custom speech (pronunciation) dictionaries must be specified in buildVars under `speechDictionaries` dictionary as follows: + +* Dictionary name (string key for a nested dictionary): each `symbolDictionaries` entry is a name for the included custom speech dictionary placed in `speechDicts` folder inside `addon` folder. +The file is named `.dic`. +This nested dictionary should specify: + * displayName (string): the name of the dictionary shown to users and is translatable. + * mandatory (True/False): Always enabled (True) or optional and visible in the GUI (False) + +Note: you must fill out this dictionary if at least one custom speech dictionary is included in the add-on. +If not, leave the dictionary empty. + ### To manage documentation files for your addon: 1. Copy the `readme.md` file for your add-on to the first created folder, where you copied `buildVars.py`. You can also copy `style.css` to improve the presentation of HTML documents. diff --git a/sconstruct b/sconstruct index 481a7ac..cdbad3f 100644 --- a/sconstruct +++ b/sconstruct @@ -61,6 +61,7 @@ env.Append( addon_info=buildVars.addon_info, brailleTables=buildVars.brailleTables, symbolDictionaries=buildVars.symbolDictionaries, + speechDictionaries=buildVars.speechDictionaries, ) if env["dev"]: diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index ff31eec..a71857d 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -13,6 +13,7 @@ - addon_info: .typing.AddonInfo - brailleTables: .typings.BrailleTables - symbolDictionaries: .typings.SymbolDictionaries +- speechDictionaries: .typings.SpeechDictionaries The following environment variables are required to build the HTML: @@ -49,6 +50,7 @@ def generate(env: Environment): env.SetDefault(brailleTables={}) env.SetDefault(symbolDictionaries={}) + env.SetDefault(speechDictionaries={}) manifestAction = env.Action( lambda target, source, env: generateManifest( @@ -57,6 +59,7 @@ def generate(env: Environment): addon_info=env["addon_info"], brailleTables=env["brailleTables"], symbolDictionaries=env["symbolDictionaries"], + speechDictionaries=env["speechDictionaries"], ) and None, lambda target, source, env: f"Generating manifest {target[0]}", @@ -75,6 +78,7 @@ def generate(env: Environment): addon_info=env["addon_info"], brailleTables=env["brailleTables"], symbolDictionaries=env["symbolDictionaries"], + speechDictionaries=env["speechDictionaries"], ) and None, lambda target, source, env: f"Generating translated manifest {target[0]}", diff --git a/site_scons/site_tools/NVDATool/manifests.py b/site_scons/site_tools/NVDATool/manifests.py index a55785e..7723b0b 100644 --- a/site_scons/site_tools/NVDATool/manifests.py +++ b/site_scons/site_tools/NVDATool/manifests.py @@ -2,7 +2,7 @@ import gettext from functools import partial -from .typings import AddonInfo, BrailleTables, SymbolDictionaries +from .typings import AddonInfo, BrailleTables, SymbolDictionaries, SpeechDictionaries from .utils import format_nested_section @@ -12,6 +12,7 @@ def generateManifest( addon_info: AddonInfo, brailleTables: BrailleTables, symbolDictionaries: SymbolDictionaries, + speechDictionaries: SpeechDictionaries, ): # Prepare the root manifest section with codecs.open(source, "r", "utf-8") as f: @@ -26,6 +27,10 @@ def generateManifest( if symbolDictionaries: manifest += format_nested_section("symbolDictionaries", symbolDictionaries) + # Custom speech pronunciation dictionaries + if speechDictionaries: + manifest += format_nested_section("speechDictionaries", speechDictionaries) + with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) @@ -38,6 +43,7 @@ def generateTranslatedManifest( addon_info: AddonInfo, brailleTables: BrailleTables, symbolDictionaries: SymbolDictionaries, + speechDictionaries: SpeechDictionaries, ): with open(mo, "rb") as f: _ = gettext.GNUTranslations(f).gettext @@ -63,5 +69,9 @@ def generateTranslatedManifest( if symbolDictionaries: manifest += _format_section_only_with_displayName("symbolDictionaries", symbolDictionaries) + # Custom speech pronunciation dictionaries + if speechDictionaries: + manifest += _format_section_only_with_displayName("speechDictionaries", speechDictionaries) + with codecs.open(dest, "w", "utf-8") as f: f.write(manifest) diff --git a/site_scons/site_tools/NVDATool/typings.py b/site_scons/site_tools/NVDATool/typings.py index 650a759..0375538 100644 --- a/site_scons/site_tools/NVDATool/typings.py +++ b/site_scons/site_tools/NVDATool/typings.py @@ -30,8 +30,14 @@ class SymbolDictionaryAttributes(TypedDict): mandatory: bool +class SpeechDictionaryAttributes(TypedDict): + displayName: str + mandatory: bool + + BrailleTables = dict[str, BrailleTableAttributes] SymbolDictionaries = dict[str, SymbolDictionaryAttributes] +SpeechDictionaries = dict[str, SpeechDictionaryAttributes] class Strable(Protocol): From bda47e6dd43fe91064647e83cd41022038282d07 Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Mon, 2 Mar 2026 19:39:09 -0700 Subject: [PATCH 351/362] BuildVars: add missing SpeechDictionaries import (#20) --- buildVars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildVars.py b/buildVars.py index decefe4..0adb36b 100644 --- a/buildVars.py +++ b/buildVars.py @@ -1,7 +1,7 @@ # Build customizations # Change this file instead of sconstruct or manifest files, whenever possible. -from site_scons.site_tools.NVDATool.typings import AddonInfo, BrailleTables, SymbolDictionaries +from site_scons.site_tools.NVDATool.typings import AddonInfo, BrailleTables, SymbolDictionaries, SpeechDictionaries # Since some strings in `addon_info` are translatable, # we need to include them in the .po files. From 3ab00214b1950a6ed432a90709203e9beb453329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 3 Mar 2026 06:48:59 +0100 Subject: [PATCH 352/362] Run workflow just when files are changed in the addon folder (#21) Currently, checks are run with GitHub Actions regardless of files which have been changed. This PR makes checks to be run just for add-ons. Additionally, Python and dependencies are installed using uv and pyproject.toml. --- .github/workflows/build_addon.yml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 63a6f1d..8585bae 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -5,9 +5,12 @@ on: tags: ["*"] # To build on main/master branch, uncomment the following line: # branches: [ main , master ] - + paths: + - addon/** pull_request: branches: [ main, master ] + paths: + - addon/** workflow_dispatch: @@ -17,22 +20,17 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt - + - name: Checkout repo + uses: actions/checkout@v6 + - name: Install uv + uses: astral-sh/setup-uv@v7 - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: 3.11 - cache: 'pip' - + run: uv python install - name: Install dependencies run: | - python -m pip install --upgrade pip wheel - pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y gettext + uv pip install - name: Code checks run: export SKIP=no-commit-to-branch; pre-commit run --all From 6093c55b53f5d56db635e21203201616ae120fdc Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Wed, 4 Mar 2026 04:32:44 +0100 Subject: [PATCH 353/362] Do not restrict workflow triggers to addon path (#22) Co-authored-by: Cyrille Bougot --- .github/workflows/build_addon.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 8585bae..a392f81 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -5,12 +5,9 @@ on: tags: ["*"] # To build on main/master branch, uncomment the following line: # branches: [ main , master ] - paths: - - addon/** + pull_request: branches: [ main, master ] - paths: - - addon/** workflow_dispatch: From e0585fd6c23102c97163fd25fcae7ce1d5cb790a Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Tue, 17 Mar 2026 06:55:42 +0100 Subject: [PATCH 354/362] Fixes for CI workflow (#23) Various CI fixes and improvements: Do not try to build / make release if the workflow is run from this add-on template repo, since it fails and the template is not meant to be used as a release. Fixes: Do not restrict workflow triggers to addon path #22 (comment). Modernized uv usage with "uv sync", fixing the failure on previously used "uv pip install". Discussed in Do not restrict workflow triggers to addon path #22 (comment). Use uv for each command using Python so that the correct environment is used Added .egg-info to .git-ignore Updated readme --- .github/workflows/build_addon.yml | 13 ++++++++----- .gitignore | 1 + readme.md | 9 +++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index a392f81..97519e4 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -13,6 +13,9 @@ on: jobs: build: + # Building the add-on template as an add-on does not make sense (and fails). + # Do not modify this repo name with your own one! (should remain the template) + if: github.repository != 'nvaccess/addonTemplate' runs-on: ubuntu-latest @@ -21,19 +24,19 @@ jobs: uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - - name: Set up Python - run: uv python install + with: + enable-cache: true - name: Install dependencies run: | sudo apt-get update -y sudo apt-get install -y gettext - uv pip install + uv sync - name: Code checks - run: export SKIP=no-commit-to-branch; pre-commit run --all + run: export SKIP=no-commit-to-branch; uv run pre-commit run --all-files - name: building addon - run: scons && scons pot + run: uv run scons && uv run scons pot - uses: actions/upload-artifact@v7 with: diff --git a/.gitignore b/.gitignore index 0be8af1..a6ccee5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ manifest.ini *.nvda-addon .sconsign.dblite /[0-9]*.[0-9]*.[0-9]*.json +*.egg-info diff --git a/readme.md b/readme.md index 117eb2c..df61be9 100644 --- a/readme.md +++ b/readme.md @@ -89,10 +89,15 @@ sconstruct and file: ``` .pre-commit-config.yaml +changelog.md +pyproject.toml +uv.lock ``` 4. Create an `addon` folder inside your new folder. You will put your code in the usual folders for NVDA extensions, under the `addon` folder. For instance: `globalPlugins`, `synthDrivers`, etc. -5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). Also, be sure to carefully set the paths contained in the other variables in that file. If you need to use custom Markdown extensions, original add-on interface language is not English, or include custom braille translations tables, be sure to fil out markdown list, base language variable, and braille tables dictioanry, respectively. +5. In the `buildVars.py` file, change variable `addon_info` with your add-on's information (name, summary, description, version, author, url, source url, license, and license URL). Also, be sure to carefully set the paths contained in the other variables in that file. If you need to use custom Markdown extensions, original add-on interface language is not English, or include custom braille translations tables, be sure to fil out markdown list, base language variable, and braille tables dictionary, respectively. 6. Gettext translations must be placed into `addon\locale\/LC_MESSAGES\nvda.po`. +7. If you create releases with the GitHub workflow, pushing a tag, update the `changelog.md` file with the release description you want to be displayed in on your GitHub release page. +8. In the `[project]` section of `pyproject.toml`, update your project information. #### Add-on manifest specification @@ -102,7 +107,7 @@ An add-on manifest generated manually or via `buildVars.py` must include the fol * Summary (string): name as shown on NVDA's Add-on store. * Description (string): a short detailed description about the add-on. * Version (string), ideally number.number with an optional third number, denoting major.minor.patch. -* Changelog (string): changes between previous and current add-on releases. +* Changelog (string): changes between previous and current add-on releases, visible in the Add-on Store. * Author (string and an email address): one or more add-on author contact information in the form "name ". * URL (string): a web address where the add-on information can be found such as add-on repository. * docFileName (string): name of the documentation file. From 867f183901d843e388af519e0a0bb6d5da45887f Mon Sep 17 00:00:00 2001 From: Cyrille Bougot Date: Thu, 19 Mar 2026 09:00:18 +0100 Subject: [PATCH 355/362] Workflow runs produce add-on and .pot artifacts instead of a .zip (#24) --- .github/workflows/build_addon.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 97519e4..62ea4f4 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -43,7 +43,14 @@ jobs: name: packaged_addon path: | ./*.nvda-addon + archive: false + + - uses: actions/upload-artifact@v7 + with: + name: translation_template + path: | ./*.pot + archive: false upload_release: runs-on: ubuntu-latest @@ -53,8 +60,11 @@ jobs: contents: write steps: - uses: actions/checkout@v6 - - name: download releases files + - name: download all artifacts uses: actions/download-artifact@v8 + with: + path: . + merge-multiple: true - name: Display structure of downloaded files run: ls -R - name: Calculate sha256 From eef379d894117719bc26e66944a6fc0824368371 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:21:35 +1100 Subject: [PATCH 356/362] Bump requests from 2.32.5 to 2.33.0 in the uv group across 1 directory (#25) Bumps the uv group with 1 update in the / directory: [requests](https://github.com/psf/requests). Updates `requests` from 2.32.5 to 2.33.0 - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.32.5...v2.33.0) --- updated-dependencies: - dependency-name: requests dependency-version: 2.33.0 dependency-type: direct:production dependency-group: uv ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index aa8752d..02e421a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ "scons==4.10.1", "Markdown==3.10", # Translations management - "requests==2.32.5", + "requests==2.33.0", "nh3==0.3.2", "crowdin-api-client==1.24.1", "lxml==6.0.2", diff --git a/uv.lock b/uv.lock index 460a161..43e6868 100644 --- a/uv.lock +++ b/uv.lock @@ -32,7 +32,7 @@ requires-dist = [ { name = "nh3", specifier = "==0.3.2" }, { name = "pre-commit", specifier = "==4.2.0" }, { name = "pyright", extras = ["nodejs"], specifier = "==1.1.407" }, - { name = "requests", specifier = "==2.32.5" }, + { name = "requests", specifier = "==2.33.0" }, { name = "ruff", specifier = "==0.14.5" }, { name = "scons", specifier = "==4.10.1" }, { name = "uv", specifier = "==0.9.11" }, @@ -324,7 +324,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.5" +version = "2.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -332,9 +332,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, + { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" }, ] [[package]] From b4c72dd5e6134e9abc85b99228bd482158e2c920 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 11:16:04 +1000 Subject: [PATCH 357/362] Bump uv from 0.9.11 to 0.11.6 in the uv group across 1 directory (#26) Bumps the uv group with 1 update in the / directory: [uv](https://github.com/astral-sh/uv). Updates `uv` from 0.9.11 to 0.11.6 - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/uv/compare/0.9.11...0.11.6) --- updated-dependencies: - dependency-name: uv dependency-version: 0.11.6 dependency-type: direct:production dependency-group: uv ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- uv.lock | 42 +++++++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 02e421a..29765be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ dependencies = [ "markdown-link-attr-modifier==0.2.1", "mdx-gh-links==0.4", # Lint - "uv==0.9.11", + "uv==0.11.6", "ruff==0.14.5", "pre-commit==4.2.0", "pyright[nodejs]==1.1.407", diff --git a/uv.lock b/uv.lock index 43e6868..6803ad0 100644 --- a/uv.lock +++ b/uv.lock @@ -35,7 +35,7 @@ requires-dist = [ { name = "requests", specifier = "==2.33.0" }, { name = "ruff", specifier = "==0.14.5" }, { name = "scons", specifier = "==4.10.1" }, - { name = "uv", specifier = "==0.9.11" }, + { name = "uv", specifier = "==0.11.6" }, ] [[package]] @@ -392,28 +392,28 @@ wheels = [ [[package]] name = "uv" -version = "0.9.11" +version = "0.11.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/08/3bf76403ea7c22feef634849137fab10b28ab5ba5bbf08a53390763d5448/uv-0.9.11.tar.gz", hash = "sha256:605a7a57f508aabd029fc0c5ef5c60a556f8c50d32e194f1a300a9f4e87f18d4", size = 3744387, upload-time = "2025-11-20T23:20:00.95Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/f3/8aceeab67ea69805293ab290e7ca8cc1b61a064d28b8a35c76d8eba063dd/uv-0.11.6.tar.gz", hash = "sha256:e3b21b7e80024c95ff339fcd147ac6fc3dd98d3613c9d45d3a1f4fd1057f127b", size = 4073298, upload-time = "2026-04-09T12:09:01.738Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/26/8f917e9faddd9cb49abcbc8c7dac5343b0f61d04c6ac36873d2a324fee1a/uv-0.9.11-py3-none-linux_armv6l.whl", hash = "sha256:803f85cf25ab7f1fca10fe2e40a1b9f5b1d48efc25efd6651ba3c9668db6a19e", size = 20787588, upload-time = "2025-11-20T23:18:53.738Z" }, - { url = "https://files.pythonhosted.org/packages/f5/1f/eafd39c719ddee19fc25884f68c1a7e736c0fca63c1cbef925caf8ebd739/uv-0.9.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6a31b0bd4eaec59bf97816aefbcd75cae4fcc8875c4b19ef1846b7bff3d67c70", size = 19922144, upload-time = "2025-11-20T23:18:57.569Z" }, - { url = "https://files.pythonhosted.org/packages/bf/f3/6b9fac39e5b65fa47dba872dcf171f1470490cd645343e8334f20f73885b/uv-0.9.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48548a23fb5a103b8955dfafff7d79d21112b8e25ce5ff25e3468dc541b20e83", size = 18380643, upload-time = "2025-11-20T23:19:01.02Z" }, - { url = "https://files.pythonhosted.org/packages/d6/9a/d4080e95950a4fc6fdf20d67b9a43ffb8e3d6d6b7c8dda460ae73ddbecd9/uv-0.9.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:cb680948e678590b5960744af2ecea6f2c0307dbb74ac44daf5c00e84ad8c09f", size = 20310262, upload-time = "2025-11-20T23:19:04.914Z" }, - { url = "https://files.pythonhosted.org/packages/6d/b4/86d9c881bd6accf2b766f7193b50e9d5815f2b34806191d90ea24967965e/uv-0.9.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9ef1982295e5aaf909a9668d6fb6abfc5089666c699f585a36f3a67f1a22916a", size = 20392988, upload-time = "2025-11-20T23:19:08.258Z" }, - { url = "https://files.pythonhosted.org/packages/a3/1d/6a227b7ca1829442c1419ba1db856d176b6e0861f9bf9355a8790a5d02b5/uv-0.9.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92ff773aa4193148019533c55382c2f9c661824bbf0c2e03f12aeefc800ede57", size = 21394892, upload-time = "2025-11-20T23:19:12.626Z" }, - { url = "https://files.pythonhosted.org/packages/5a/8f/df45b8409923121de8c4081c9d6d8ba3273eaa450645e1e542d83179c7b5/uv-0.9.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:70137a46675bbecf3a8b43d292a61767f1b944156af3d0f8d5986292bd86f6cf", size = 22987735, upload-time = "2025-11-20T23:19:16.27Z" }, - { url = "https://files.pythonhosted.org/packages/89/51/bbf3248a619c9f502d310a11362da5ed72c312d354fb8f9667c5aa3be9dd/uv-0.9.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5af9117bab6c4b3a1cacb0cddfb3cd540d0adfb13c7b8a9a318873cf2d07e52", size = 22617321, upload-time = "2025-11-20T23:19:20.1Z" }, - { url = "https://files.pythonhosted.org/packages/3f/cd/a158ec989c5433dc86ebd9fea800f2aed24255b84ab65b6d7407251e5e31/uv-0.9.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8cc86940d9b3a425575f25dc45247be2fb31f7fed7bf3394ae9daadd466e5b80", size = 21615712, upload-time = "2025-11-20T23:19:23.71Z" }, - { url = "https://files.pythonhosted.org/packages/73/da/2597becbc0fcbb59608d38fda5db79969e76dedf5b072f0e8564c8f0628b/uv-0.9.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e97906ca1b90dac91c23af20e282e2e37c8eb80c3721898733928a295f2defda", size = 21661022, upload-time = "2025-11-20T23:19:27.385Z" }, - { url = "https://files.pythonhosted.org/packages/52/66/9b8f3b3529b23c2a6f5b9612da70ea53117935ec999757b4f1d640f63d63/uv-0.9.11-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:d901269e1db72abc974ba61d37be6e56532e104922329e0b553d9df07ba224be", size = 20440548, upload-time = "2025-11-20T23:19:31.051Z" }, - { url = "https://files.pythonhosted.org/packages/72/b2/683afdb83e96dd966eb7cf3688af56a1b826c8bc1e8182fb10ec35b3e391/uv-0.9.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:8abfb7d4b136de3e92dd239ea9a51d4b7bbb970dc1b33bec84d08facf82b9a6e", size = 21493758, upload-time = "2025-11-20T23:19:34.688Z" }, - { url = "https://files.pythonhosted.org/packages/f4/00/99848bc9834aab104fa74aa1a60b1ca478dee824d2e4aacb15af85673572/uv-0.9.11-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:1f8afc13b3b94bce1e72514c598d41623387b2b61b68d7dbce9a01a0d8874860", size = 20332324, upload-time = "2025-11-20T23:19:38.376Z" }, - { url = "https://files.pythonhosted.org/packages/6c/94/8cfd1bb1cc5d768cb334f976ba2686c6327e4ac91c16b8469b284956d4d9/uv-0.9.11-py3-none-musllinux_1_1_i686.whl", hash = "sha256:7d414cfa410f1850a244d87255f98d06ca61cc13d82f6413c4f03e9e0c9effc7", size = 20845062, upload-time = "2025-11-20T23:19:42.006Z" }, - { url = "https://files.pythonhosted.org/packages/a0/42/43f66bfc621464dabe9cfe3cbf69cddc36464da56ab786c94fc9ccf99cc7/uv-0.9.11-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:edc14143d0ba086a7da4b737a77746bb36bc00e3d26466f180ea99e3bf795171", size = 21857559, upload-time = "2025-11-20T23:19:46.026Z" }, - { url = "https://files.pythonhosted.org/packages/8f/4d/bfd41bf087522601c724d712c3727aeb62f51b1f67c4ab86a078c3947525/uv-0.9.11-py3-none-win32.whl", hash = "sha256:af5fd91eecaa04b4799f553c726307200f45da844d5c7c5880d64db4debdd5dc", size = 19639246, upload-time = "2025-11-20T23:19:50.254Z" }, - { url = "https://files.pythonhosted.org/packages/2c/2f/d51c02627de68a7ca5b82f0a5d61d753beee3fe696366d1a1c5d5e40cd58/uv-0.9.11-py3-none-win_amd64.whl", hash = "sha256:c65a024ad98547e32168f3a52360fe73ff39cd609a8fb9dd2509aac91483cfc8", size = 21626822, upload-time = "2025-11-20T23:19:54.424Z" }, - { url = "https://files.pythonhosted.org/packages/af/d8/e07e866ee328d3c9f27a6d57a018d8330f47be95ef4654a178779c968a66/uv-0.9.11-py3-none-win_arm64.whl", hash = "sha256:4907a696c745703542ed2559bdf5380b92c8b1d4bf290ebfed45bf9a2a2c6690", size = 20046856, upload-time = "2025-11-20T23:19:58.517Z" }, + { url = "https://files.pythonhosted.org/packages/1f/fe/4b61a3d5ad9d02e8a4405026ccd43593d7044598e0fa47d892d4dafe44c9/uv-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:ada04dcf89ddea5b69d27ac9cdc5ef575a82f90a209a1392e930de504b2321d6", size = 23780079, upload-time = "2026-04-09T12:08:56.609Z" }, + { url = "https://files.pythonhosted.org/packages/52/db/d27519a9e1a5ffee9d71af1a811ad0e19ce7ab9ae815453bef39dd479389/uv-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5be013888420f96879c6e0d3081e7bcf51b539b034a01777041934457dfbedf3", size = 23214721, upload-time = "2026-04-09T12:09:32.228Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8f/4399fa8b882bd7e0efffc829f73ab24d117d490a93e6bc7104a50282b854/uv-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ffa5dc1cbb52bdce3b8447e83d1601a57ad4da6b523d77d4b47366db8b1ceb18", size = 21750109, upload-time = "2026-04-09T12:09:24.357Z" }, + { url = "https://files.pythonhosted.org/packages/32/07/5a12944c31c3dda253632da7a363edddb869ed47839d4d92a2dc5f546c93/uv-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:bfb107b4dade1d2c9e572992b06992d51dd5f2136eb8ceee9e62dd124289e825", size = 23551146, upload-time = "2026-04-09T12:09:10.439Z" }, + { url = "https://files.pythonhosted.org/packages/79/5b/2ec8b0af80acd1016ed596baf205ddc77b19ece288473b01926c4a9cf6db/uv-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:9e2fe7ce12161d8016b7deb1eaad7905a76ff7afec13383333ca75e0c4b5425d", size = 23331192, upload-time = "2026-04-09T12:09:34.792Z" }, + { url = "https://files.pythonhosted.org/packages/62/7d/eea35935f2112b21c296a3e42645f3e4b1aa8bcd34dcf13345fbd55134b7/uv-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ed9c6f70c25e8dfeedddf4eddaf14d353f5e6b0eb43da9a14d3a1033d51d915", size = 23337686, upload-time = "2026-04-09T12:09:18.522Z" }, + { url = "https://files.pythonhosted.org/packages/21/47/2584f5ab618f6ebe9bdefb2f765f2ca8540e9d739667606a916b35449eec/uv-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d68a013e609cebf82077cbeeb0809ed5e205257814273bfd31e02fc0353bbfc2", size = 25008139, upload-time = "2026-04-09T12:09:03.983Z" }, + { url = "https://files.pythonhosted.org/packages/95/81/497ae5c1d36355b56b97dc59f550c7e89d0291c163a3f203c6f341dff195/uv-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93f736dddca03dae732c6fdea177328d3bc4bf137c75248f3d433c57416a4311", size = 25712458, upload-time = "2026-04-09T12:09:07.598Z" }, + { url = "https://files.pythonhosted.org/packages/3c/1c/74083238e4fab2672b63575b9008f1ea418b02a714bcfcf017f4f6a309b6/uv-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e96a66abe53fced0e3389008b8d2eff8278cfa8bb545d75631ae8ceb9c929aba", size = 24915507, upload-time = "2026-04-09T12:08:50.892Z" }, + { url = "https://files.pythonhosted.org/packages/5a/ee/e14fe10ba455a823ed18233f12de6699a601890905420b5c504abf115116/uv-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b096311b2743b228df911a19532b3f18fa420bf9530547aecd6a8e04bbfaccd", size = 24971011, upload-time = "2026-04-09T12:08:54.016Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a1/7b9c83eaadf98e343317ff6384a7227a4855afd02cdaf9696bcc71ee6155/uv-0.11.6-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:904d537b4a6e798015b4a64ff5622023bd4601b43b6cd1e5f423d63471f5e948", size = 23640234, upload-time = "2026-04-09T12:09:15.735Z" }, + { url = "https://files.pythonhosted.org/packages/d6/51/75ccdd23e76ff1703b70eb82881cd5b4d2a954c9679f8ef7e0136ef2cfab/uv-0.11.6-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:4ed8150c26b5e319381d75ae2ce6aba1e9c65888f4850f4e3b3fa839953c90a5", size = 24452664, upload-time = "2026-04-09T12:09:26.875Z" }, + { url = "https://files.pythonhosted.org/packages/4d/86/ace80fe47d8d48b5e3b5aee0b6eb1a49deaacc2313782870250b3faa36f5/uv-0.11.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:1c9218c8d4ac35ca6e617fb0951cc0ab2d907c91a6aea2617de0a5494cf162c0", size = 24494599, upload-time = "2026-04-09T12:09:37.368Z" }, + { url = "https://files.pythonhosted.org/packages/05/2d/4b642669b56648194f026de79bc992cbfc3ac2318b0a8d435f3c284934e8/uv-0.11.6-py3-none-musllinux_1_1_i686.whl", hash = "sha256:9e211c83cc890c569b86a4183fcf5f8b6f0c7adc33a839b699a98d30f1310d3a", size = 24159150, upload-time = "2026-04-09T12:09:13.17Z" }, + { url = "https://files.pythonhosted.org/packages/ae/24/7eecd76fe983a74fed1fc700a14882e70c4e857f1d562a9f2303d4286c12/uv-0.11.6-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d2a1d2089afdf117ad19a4c1dd36b8189c00ae1ad4135d3bfbfced82342595cf", size = 25164324, upload-time = "2026-04-09T12:08:59.56Z" }, + { url = "https://files.pythonhosted.org/packages/27/e0/bbd4ba7c2e5067bbba617d87d306ec146889edaeeaa2081d3e122178ca08/uv-0.11.6-py3-none-win32.whl", hash = "sha256:6e8344f38fa29f85dcfd3e62dc35a700d2448f8e90381077ef393438dcd5012e", size = 22865693, upload-time = "2026-04-09T12:09:21.415Z" }, + { url = "https://files.pythonhosted.org/packages/a5/33/1983ce113c538a856f2d620d16e39691962ecceef091a84086c5785e32e5/uv-0.11.6-py3-none-win_amd64.whl", hash = "sha256:a28bea69c1186303d1200f155c7a28c449f8a4431e458fcf89360cc7ef546e40", size = 25371258, upload-time = "2026-04-09T12:09:40.52Z" }, + { url = "https://files.pythonhosted.org/packages/35/01/be0873f44b9c9bc250fcbf263367fcfc1f59feab996355bcb6b52fff080d/uv-0.11.6-py3-none-win_arm64.whl", hash = "sha256:a78f6d64b9950e24061bc7ec7f15ff8089ad7f5a976e7b65fcadce58fe02f613", size = 23869585, upload-time = "2026-04-09T12:09:29.425Z" }, ] [[package]] From dab00d50bccbc5d226fd0dde7a2029cdf306b082 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 09:10:45 +1000 Subject: [PATCH 358/362] Bump softprops/action-gh-release from 2 to 3 (#27) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_addon.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml index 62ea4f4..bbd563f 100644 --- a/.github/workflows/build_addon.yml +++ b/.github/workflows/build_addon.yml @@ -73,7 +73,7 @@ jobs: sha256sum *.nvda-addon >> changelog.md - name: Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: files: | *.nvda-addon From b6443deab71ed67d5dc91b183e01834016bcdc39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:07:44 +1000 Subject: [PATCH 359/362] Bump lxml from 6.0.2 to 6.1.0 in the uv group across 1 directory (#29) Bumps the uv group with 1 update in the / directory: [lxml](https://github.com/lxml/lxml). Updates `lxml` from 6.0.2 to 6.1.0 - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](https://github.com/lxml/lxml/compare/lxml-6.0.2...lxml-6.1.0) --- updated-dependencies: - dependency-name: lxml dependency-version: 6.1.0 dependency-type: direct:production dependency-group: uv ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- uv.lock | 42 +++++++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 29765be..19f3359 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "requests==2.33.0", "nh3==0.3.2", "crowdin-api-client==1.24.1", - "lxml==6.0.2", + "lxml==6.1.0", "mdx_truly_sane_lists==1.3", "markdown-link-attr-modifier==0.2.1", "mdx-gh-links==0.4", diff --git a/uv.lock b/uv.lock index 6803ad0..81dbe96 100644 --- a/uv.lock +++ b/uv.lock @@ -24,7 +24,7 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "crowdin-api-client", specifier = "==1.24.1" }, - { name = "lxml", specifier = "==6.0.2" }, + { name = "lxml", specifier = "==6.1.0" }, { name = "markdown", specifier = "==3.10" }, { name = "markdown-link-attr-modifier", specifier = "==0.2.1" }, { name = "mdx-gh-links", specifier = "==0.4" }, @@ -144,28 +144,28 @@ wheels = [ [[package]] name = "lxml" -version = "6.0.2" +version = "6.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/30/9abc9e34c657c33834eaf6cd02124c61bdf5944d802aa48e69be8da3585d/lxml-6.1.0.tar.gz", hash = "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13", size = 4197006, upload-time = "2026-04-18T04:32:51.613Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, - { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, - { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, - { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, - { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, - { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, - { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, - { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, - { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, - { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, - { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, - { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, - { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, - { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/08/03/69347590f1cf4a6d5a4944bb6099e6d37f334784f16062234e1f892fdb1d/lxml-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45", size = 8559689, upload-time = "2026-04-18T04:31:57.785Z" }, + { url = "https://files.pythonhosted.org/packages/3f/58/25e00bb40b185c974cfe156c110474d9a8a8390d5f7c92a4e328189bb60e/lxml-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d", size = 4617892, upload-time = "2026-04-18T04:32:01.78Z" }, + { url = "https://files.pythonhosted.org/packages/f5/54/92ad98a94ac318dc4f97aaac22ff8d1b94212b2ae8af5b6e9b354bf825f7/lxml-6.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2", size = 4923489, upload-time = "2026-04-18T04:33:31.401Z" }, + { url = "https://files.pythonhosted.org/packages/15/3b/a20aecfab42bdf4f9b390590d345857ad3ffd7c51988d1c89c53a0c73faf/lxml-6.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491", size = 5082162, upload-time = "2026-04-18T04:33:34.262Z" }, + { url = "https://files.pythonhosted.org/packages/45/26/2cdb3d281ac1bd175603e290cbe4bad6eff127c0f8de90bafd6f8548f0fd/lxml-6.1.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc", size = 4993247, upload-time = "2026-04-18T04:33:36.674Z" }, + { url = "https://files.pythonhosted.org/packages/f6/05/d735aef963740022a08185c84821f689fc903acb3d50326e6b1e9886cc22/lxml-6.1.0-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e", size = 5613042, upload-time = "2026-04-18T04:33:39.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b8/ead7c10efff731738c72e59ed6eb5791854879fbed7ae98781a12006263a/lxml-6.1.0-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2", size = 5228304, upload-time = "2026-04-18T04:33:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/6b/10/e9842d2ec322ea65f0a7270aa0315a53abed06058b88ef1b027f620e7a5f/lxml-6.1.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9", size = 5341578, upload-time = "2026-04-18T04:33:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/89/54/40d9403d7c2775fa7301d3ddd3464689bfe9ba71acc17dfff777071b4fdc/lxml-6.1.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe", size = 4700209, upload-time = "2026-04-18T04:33:47.552Z" }, + { url = "https://files.pythonhosted.org/packages/85/b2/bbdcc2cf45dfc7dfffef4fd97e5c47b15919b6a365247d95d6f684ef5e82/lxml-6.1.0-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88", size = 5232365, upload-time = "2026-04-18T04:33:50.249Z" }, + { url = "https://files.pythonhosted.org/packages/48/5a/b06875665e53aaba7127611a7bed3b7b9658e20b22bc2dd217a0b7ab0091/lxml-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181", size = 5043654, upload-time = "2026-04-18T04:33:52.71Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9c/e71a069d09641c1a7abeb30e693f828c7c90a41cbe3d650b2d734d876f85/lxml-6.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24", size = 4769326, upload-time = "2026-04-18T04:33:55.244Z" }, + { url = "https://files.pythonhosted.org/packages/cc/06/7a9cd84b3d4ed79adf35f874750abb697dec0b4a81a836037b36e47c091a/lxml-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e", size = 5635879, upload-time = "2026-04-18T04:33:58.509Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f0/9d57916befc1e54c451712c7ee48e9e74e80ae4d03bdce49914e0aee42cd/lxml-6.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495", size = 5224048, upload-time = "2026-04-18T04:34:00.943Z" }, + { url = "https://files.pythonhosted.org/packages/99/75/90c4eefda0c08c92221fe0753db2d6699a4c628f76ff4465ec20dea84cc1/lxml-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33", size = 5250241, upload-time = "2026-04-18T04:34:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/5e/73/16596f7e4e38fa33084b9ccbccc22a15f82a290a055126f2c1541236d2ff/lxml-6.1.0-cp313-cp313-win32.whl", hash = "sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62", size = 3596938, upload-time = "2026-04-18T04:31:56.206Z" }, + { url = "https://files.pythonhosted.org/packages/8e/63/981401c5680c1eb30893f00a19641ac80db5d1e7086c62cb4b13ed813038/lxml-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16", size = 3995728, upload-time = "2026-04-18T04:31:58.763Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e8/c358a38ac3e541d16a1b527e4e9cb78c0419b0506a070ace11777e5e8404/lxml-6.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d", size = 3658372, upload-time = "2026-04-18T04:32:03.629Z" }, ] [[package]] From ef8c343093f3567a6354124c8f7f3de7afc20931 Mon Sep 17 00:00:00 2001 From: Nikita Tseykovets Date: Mon, 4 May 2026 07:23:19 +0300 Subject: [PATCH 360/362] Update link to the GetText build for Windows (#30) * Update link to the GetText build for Windows * Apply suggestion from @seanbudd --------- Co-authored-by: Sean Budd --- readme.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index df61be9..6b1ecfd 100644 --- a/readme.md +++ b/readme.md @@ -58,7 +58,10 @@ You need the following software to use this code for your NVDA add-on developmen * a Python distribution (3.13 64-bit or later is recommended). Check the [Python Website](https://www.python.org) for Windows Installers. * Scons - [Website](https://www.scons.org/) - version 4.10.1 or later. You can install it via PIP. -* GNU Gettext tools, if you want to have localization support for your add-on - Recommended. Any Linux distro or cygwin have those installed. You can find windows builds [here](https://gnuwin32.sourceforge.net/downlinks/gettext.php). +* GNU Gettext tools (recommended). +Needed if you want to have localization support for your add-on. +Any Linux distro or cygwin have those installed. +You can find Windows builds [here](https://mlocati.github.io/articles/gettext-iconv-windows.html). * Markdown 3.8.2 or later, if you want to convert documentation files to HTML documents. You can install it via PIP. * Optional: additional tools such as linters and type checkers defined in pyproject.toml file. From e3a6ab411213436c21cdfce802331543ae5ab450 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 12:33:47 +1000 Subject: [PATCH 361/362] Bump urllib3 from 2.6.3 to 2.7.0 in the uv group across 1 directory (#32) Bumps the uv group with 1 update in the / directory: [urllib3](https://github.com/urllib3/urllib3). Updates `urllib3` from 2.6.3 to 2.7.0 - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.6.3...2.7.0) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.7.0 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index 81dbe96..7809638 100644 --- a/uv.lock +++ b/uv.lock @@ -383,11 +383,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.3" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, ] [[package]] From aba4902cbbbcbad34fc6ae81088eafa816c1fe53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 May 2026 08:54:26 +1000 Subject: [PATCH 362/362] Bump idna from 3.11 to 3.15 in the uv group across 1 directory (#33) Bumps the uv group with 1 update in the / directory: [idna](https://github.com/kjd/idna). Updates `idna` from 3.11 to 3.15 - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.md) - [Commits](https://github.com/kjd/idna/compare/v3.11...v3.15) --- updated-dependencies: - dependency-name: idna dependency-version: '3.15' dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index 7809638..803acd5 100644 --- a/uv.lock +++ b/uv.lock @@ -135,11 +135,11 @@ wheels = [ [[package]] name = "idna" -version = "3.11" +version = "3.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/77/7b3966d0b9d1d31a36ddf1746926a11dface89a83409bf1483f0237aa758/idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc", size = 199245, upload-time = "2026-05-12T22:45:57.011Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8", size = 72340, upload-time = "2026-05-12T22:45:55.733Z" }, ] [[package]]