Skip to content

Firedrake coding guide

Connor Ward edited this page Sep 24, 2026 · 5 revisions

Coding style

  • PEP 8 should be followed.
  • f-strings should be preferred to the older style % and .format() string formatting methods. A possible exception to this is with large multi-line strings where .format() may be more readable.
  • Excessively long functions (50 lines+) should ideally be broken apart into more readable pieces.
  • * imports should be avoided inside the __init__.py files inside Firedrake. This is so that we have explicit control over what goes into the firedrake namespace.
  • Unicode characters should not be used for variable names as they are hard to use in many editors. Unicode is encouraged in docstrings.

Type hinting

  • Type hinting should be used throughout. It is not necessary in the test suite.

Type hinting tips + tricks

  • To avoid issues with forward references (until Python 3.14) you should add the line from __future__ import annotations to the top of the file.
  • To avoid issues with circular imports you should do
if typing.TYPE_CHECKING:
    from firedrake import Function  # assuming that this is a circular dependency

Docstrings

  • PEP 257 (docstrings) should be followed.
  • Docstrings should be written in numpydoc format. Since type hinting is used it is not necessary to specify the type of function arguments in the docstring (unfortunately the return type still needs to be documented, ref). Occasionally it is fine to have a different type description in the numpydoc if it would otherwise expose a complicated internal detail (e.g. WithGeometry vs FunctionSpace).

Existing code

If changes are made to existing code that does not already conform to this guide, then the code should be rewritten to be conforming as part of the change.

Parallel code

Code that involves explicit MPI communications should use pyop2.mpi.temp_internal_comm. For example, instead of doing:

gvalue = mesh.comm.allreduce(value)

Do the following instead:

with pyop2.mpi.temp_internal_comm(mesh.comm) as icomm:
  gvalue = icomm.allreduce(value)

This is because we do not want to be sending messages using the user facing comm in case of conflicts.

Documentation

Linkcheck

In order for a PR to be merged then all tests including the linkcheck must be passing. If linkcheck is failing it is the responsibility of the PR author to to fix it as part of the PR. The only cases where a PR can be merged with a failing linkcheck are:

  1. The PR is authored by an external contributor (i.e. not a member of the core team). This is to avoid putting them off from contributing in future.
  2. The PR contains a critical fix (e.g. that is breaking users installations).

Other policies

  • Untaped parts of the interface should raise an exception if taping is enabled (minutes)

Clone this wiki locally