Code Style¶
Code Formatting¶
Follow existing code style (black) and conventions
Maintain consistent indentation and spacing
When initializing NumPy arrays (e.g., using
np.zeros,np.ones,np.empty, etc.), always specify thedtypeparameter (e.g.,dtype=float,dtype=int,dtype=object, etc.)In runtime strings such as error and log messages, name str values in double quotes, as the docstring rules in Type Hints and Docstrings do. Black then keeps the outer string single-quoted to avoid escapes (
f'force_method must be "joukowski" or "katz", got "{force_method}".'). Write the value inline with double quotes rather than through!r, which always emits single quotes.
Variable Naming¶
Use descriptive variable names that clearly indicate their purpose
Use underscores for variable names
CRITICAL: Follow the formalized coordinate system naming conventions exactly as described in the Axes, Points, and Frames and Angle Vectors and Transformations documents when naming vector-valued variables or things such as transformation and rotation matrices.
Do not use
wcs(or any other abbreviation) for "wing cross section" orWingCrossSectionin variable names. Instead, always write it out in full (e.g.,wing_cross_section,wing_cross_section_movement, etc.). Exception: a capitalization variant ofwcsis allowed when the name is written in exactly one of the forms required by the Axes, Points, and Frames or Angle Vectors and Transformations documents (e.g., the axes IDs inangles_Wcsp_to_Wcs_ixyzand the point IDs inLp_Wcsp_Lpp).For non-vector-valued variables whose values are in radians-based units (rad, rad/s, rad/s^2, etc.), append
_radto the variable name. Noting the units in a docstring or comment alone is not enough. Vector-valued variables and their components instead mark radians withRadin their camelCase portions, as described in the Angle Vectors and Transformations document.When naming collections of vector-valued quantities, use the
stack,grid, andlistcamelCase prefixes as described in the Axes, Points, and Frames document.Name module-level constants in UPPER_SNAKE_CASE (e.g.,
SEED,FOUR_PI,PACKAGE_LOGGER_NAME). Module-level names never start with an underscore, except inpterasoftware/__init__.py. There are three exceptions to the casing rule. First, module-level names that hold state rather than a constant value stay lowercase (e.g.,logger,solve_loop_lock, andindent_level). Second, a constant whose name is written in one of the forms required by the Axes, Points, and Frames or Angle Vectors and Transformations documents keeps that spelling (e.g.,freeFlightCameraOffsetDirection_E). Third, a module-level name that an external tool reads by a fixed name keeps that name (e.g., the Sphinx configuration values indocs/website/conf.py, such asprojectandhtml_theme).Define module-level constants after the imports and before the first function or class. There are two exceptions. First, a constant whose value calls a function defined in the same file goes after that function (e.g.,
SEQUENTIAL_COLOR_MAPin_colormaps.py). Second, in a script that runs from top to bottom, such asvalidation/validation_study.py, a constant may sit just above the step that uses it.In variable names, refer to a simulation time increment as a step (e.g.,
step,num_steps,step_discards).time_stepis also acceptable, but never usetimestep.
Running Black¶
Black is configured as a pre-commit hook. Run it with:
pre-commit run --all-files black
Running codespell¶
codespell is configured as a pre-commit hook. Run it with:
pre-commit run --all-files codespell
Running mypy¶
mypy is configured as a pre-commit hook. Run it with:
pre-commit run --all-files mypy
Imports¶
Import Ptera Software using the following pattern:
import pterasoftware as psBy default, place import statements at the top of the file and avoid imports inside functions or methods. The only exceptions are intentional lazy-import patterns (for example, using
importlib.import_moduleinside__getattr__for lazy loading) and cases where there is no other way to avoid circular imports.
Internal Names and Access¶
A leading underscore marks a name as outside the public API. It does not mark a name as off limits to the rest of the package.
Any module in
pterasoftware/, and any test, may import, read, call, and write any internal name, subject to the contracts in Classes and Immutability. Those contracts, not the underscore, decide who may write a value. Do not add# noinspection PyProtectedMemberpragmas or registration patterns to reach an internal name.Code outside the package (
examples/, the notebooks intutorials/,validation/,scripts/, and the README) uses only Ptera Software's public names. Theprivate-accesspre-commit hook enforces this. Run it with:
pre-commit run --all-files private-access
Miscellaneous Guidelines¶
Use
np.deg2radandnp.rad2degfor angle conversions instead ofnp.radiansandnp.degreesor manual conversions.