In limited circumstances, NV Access may accept contributions that do not follow these coding standards. If you’re unable to follow these standards, please make note of this when opening your PR.
General Guidelines
In general, Python contributions to NVDA should follow the PEP 8 style guide, except where it contradicts the specific guidance below. Python code style is enforced with the Ruff linter. See linting your changes for more information.Encoding
- Python files should be encoded in UTF-8
- Text files should be committed with
LFline endings - Files can be checked out locally using CRLF if needed for Windows development using git’s core.autocrlf setting
Indentation
- When splitting a single statement over multiple lines, just indent one or more additional levels
- Don’t use vertical alignment (lining up with the bracket on the previous line)
- This requires a new-line after an opening parenthesis/bracket/brace if you intend to split the statement over multiple lines
Identifier Names
Use Descriptive Names
- Name constants to avoid “magic numbers” and hint at intent or origin of the value
- Consider: what does this represent?
Functions, Variables, Properties
Use mixed case to separate words, starting with a lower case letter:Boolean Functions or Variables
- Use the positive form of the language (avoid double negatives like
shouldNotDoSomething = False) - Start with a “question word” to hint at their boolean nature
Classes
Use mixed case to separate words, starting with an upper case letter:Constants
All upper case, separating words with underscores:Scripts
Scripts (the targets of gestures) are prefixed withscript_, with subsequent words in camel case:
Event Handlers
Prefixed withevent_, with subsequent words in camel case. Note that object and action are separated by underscores:
object refers to the class type that the action refers to.
Extension Points
Action:- Prefixed with
pre_orpost_to specify that handlers are notified before/after the action
- Prefixed with
should_to turn them into a question - Example:
should_doSomething
- Prefixed with
filter_ - Should describe the filtering action and the data being returned
- Should communicate if filtering happens before or after some action
- Example:
filter_displaySize_preRefresh
Enums
Formatted using the expected mix of the above:Translatable Strings
All strings that could be presented to the user should be marked as translatable using the_() function:
Multi-line Translatable Strings
Lengthy strings can be split across multiple lines using Python’s implicit line joining inside parentheses:Imports
- Unused imports should be removed where possible
- Anything imported into a (sub)module can also be imported from that submodule
- Removing unused imports may break compatibility and should be done in compatibility breaking releases
Handling Unused Import Warnings
Unused imports will give a lint warning. Handle them in these ways:-
If imports are intended for re-export: Include them in
__all__definition -
Otherwise: Add a comment like
# noqa: <explanation>
Considering Future Backwards Compatibility
When writing new code, consider how it can be moved in future while retaining backwards compatibility. See deprecations documentation for limitations.Docstrings
Docstrings should use Sphinx format without types and follow PEP 257 conventions.When to Use Docstrings
- All public functions, classes, and methods should have docstrings
- Most internal functions, classes and methods should have docstrings, except where their purpose is clear from their name or code
- A function of more than a few lines of code is most likely not self-explanatory
Guidelines
- Providing type information in docstrings is discouraged - use type annotations instead
- Class-level and module-level docstrings should contain:
- High-level overview
- Optionally: usage examples and references to commonly used methods/functions and attributes
- Document class constructors in
__init__, not at the top of the class - Document class attributes and non-obvious public variables in a docstring immediately below the attribute
NVDA formerly used epytext syntax for docstrings, which means there is inconsistent syntax in the codebase. Issue #12971 tracks converting epytext docstrings to Sphinx.
Learning Resources
- reStructuredText Primer from Sphinx docs
- reStructuredText markup from Python Developer’s Guide
- Sphinx’s custom reStructuredText Directives
- Sphinx’s Python Domain
Type Hints
Type hints make reasoning about code much easier and allow static analysis tools to catch common errors.Requirements
- All variables, attributes, properties, and function/method arguments and returns should have type hints
- No need to provide type hints for
selforclsarguments to object/class methods - Prefer union shorthand (
X | Y) over explicitly usingtyping.Union - Corollary: prefer
T | Noneovertyping.Optional[T]
Example
Calling Non-Python Code
When using parts of the Windows API or parts of NVDA implemented in C++, use the ctypes library.Naming Conventions
- Example:
GetModuleFileNamenotgetModuleFileName - Pythonic names should be reserved for wrappers that provide more pythonic access to functions
Organization
- Windows API functions: Define in the
winBindingspackage in modules named according to the DLL- Example:
winBindings.kernel32
- Example:
- nvdaHelper ctypes code: Define in the
NVDAHelper.localLibmodule
Language Choices
The NVDA community is large and diverse. We have a responsibility to make everyone feel welcome. As our contributor code of conduct states:Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society.
Guidelines
- Avoid metaphors, euphemisms or other language with layers of meaning or negative history
- Avoid generalisations about people, cultures or countries
- Avoid ableist language
- Use gender-inclusive terminology
Examples of Preferred Terms
| Instead of | Use |
|---|---|
| master/slave | leader/follower, primary/replica |
| blacklist/whitelist | blocklist/allowlist |
| sanity check | confidence check |
| dummy (value) | placeholder |
| he/him/his (unknown gender) | they/them/theirs |
