Coding Standards#

Aviary uses a combination of formal standards and general best practices. To contribute code to the Aviary codebase, we request you follow these guidelines.

In general, always follow the excellent advice given in the PEP 8 Python style guide. Consistency is also key - pick a convention and stick with it for an entire file.

Style and Formatting#

The Aviary development team uses the autopep8 formatter to handle formatting in a consistent way across the codebase. Autopep8 is a tool that formats Python code (through alteration of whitespace and line breaks) to follow a consistent style and attempt to keep lines within the character limit whenever possible. Aviary uses autopep8 as part of its pre-commit scripts. The only required setting (which Aviary automatically enforces) is max_line_length = 89. Use of the aggressive or experimental flag is optional and up to the user, but take care that these settings do not alter code function or significantly hamper readability. The utility isort is also recommended for formatting of import statements (something not specifically handled by autopep8), but it is currently not required.

Pre-Commit Setup#

To set up pre-commit in your development python environment, there are a few one-time steps that must be done. The following commands need to be run to install pre-commit.

pip install pre-commit

pre-commit install

The Aviary repository contains a configuration file that defines what is run when commits are made and with what options enabled. Currently this is limited to autopep8 with a max line length restriction.

Controlling Display Levels#

To make debugging issues easier, it is strongly recommended to make use of the Verbosity setting. This allows control over how much information is displayed to a user; too much information makes finding relevant information difficult and not enough information can make tracking difficult. Aviary uses a sliding scale of possible verbosity settings:

Verbosity Level

Numerical Value

Description

QUIET

0

All output except errors are suppressed

BRIEF

1

Only important information is output, in human-readable format

VERBOSE

2

All user-relevant information is output, in human-readable format

DEBUG

3

Any information can be outputted, including warnings, intermediate calculations, etc., with no formatting requirement

Verbosity levels are defined in Aviary using the Verbosity Enum. Each verbosity level is paired with an integer value. In source code, verbosity level can be checked either through comparison with the Enum, or through equality or inequality comparisons with the matching integer value. This allows for code to be triggered not just at a specific level, but for any level above or below the desired setting. Numerical comparisons are recommended for several reasons: they don’t require importing the Verbosity Enum, and activation is more flexible through the use of inequality comparators, preventing issues like a message only being outputted during BRIEF but not VERBOSE or DEBUG, which a user would expect to also see in higher verbosity settings. BRIEF is default setting and is used in most cases; however, QUIET should be used for tests.

It is preferred that within source code, the full Enums are used for better readability (e.g. Verbosity.BRIEF). For tests, scripts, examples, and other places where Aviary is called (rather than defined), it is ok to use the integer representations of verbosity to shorten lines and remove the need to import the Verbosity Enum (e.g. passing 0 as the verbosity argument to a function when QUIET is desired). Of course, it is always acceptable to use the full Enum in these cases for the same readability reasons.

Naming Conventions#

Variables#

When it comes to variable naming, always be verbose! The Aviary team considers long but clear and descriptive names superior to shortened or vague names. Typing out a long name is only difficult once, as most IDEs will help you auto-complete long variable names, but the readability they add lasts a lifetime! The Aviary variable hierarchy is an excellent example of good variable naming. When adding variables to the hierarchy, adhering to the following naming conventions is requested. Inside the codebase itself, such as inside openMDAO components, it is not required but still highly recommended to follow these guidelines.

A good variable name should:

  1. Not be ambiguous (avoid names that cannot be understood without context, like x or calc)

  2. Avoid abbreviation (thrust_to_weight_ratio preferred to T_W_ratio). Note that Aviary will sometimes still shorten extremely long words such as “miscellaneous” to “misc” - use your best judgement!

  3. Use physical descriptions rather than jargon or mathematical symbols (density preferred to rho - even better, include what flight condition this density is at, such as current, sea_level, etc.)

  4. Place adjectives or modifiers after the “main” variable name rather than before (such as thrust_max, thrust_sea_level_static). This makes it is easier to autocomplete using an IDE - simply typing “thrust” will provide you with a handy list of all of the different kinds of thrust you can use.

  5. Be formatted in “snake case”, or all lowercase with underscore-delineated words (such as example_variable)

Classes#

Class names should be written in “CamelCase”, or naming with no delimiters such as dashes or underscores between words and each word beginning with a capital letter.

Functions and Methods#

Function and method names, similar to variables, should be formatted in “snake case”. Class methods that are not intended to be accessed outside of the class definition can append an underscore at the beginning of the method name to mark it as “private”, to help other users avoid using those methods incorrectly. An example of this is: def _private_method(self):

Import statements#

Autopep8 allows both absolute and relative paths in import statements. Aviary will use absolute path option only. Following autopep8, imports should be grouped in the following order:

1. Standard library imports.
2. Related third party imports.
3. Local application/library specific imports.

There should be a blank line between each group of imports.

Code Re-Use and Utility Functions#

If an identical block of code appears multiple times inside a file, consider moving it to a function to make your code cleaner. Repeated code bloats files and makes them less readable. If that function ends up being useful outside that individual file, move it to a “utils.py” file in the lowest-level directory shared by all files that need that function. If the utility function is useful across all of Aviary and is integral to the tool’s operation, the aviary/utils folder is the appropriate place for it.