Coding standards

Guide to coding standards for Q-CTRL projects


Hierarchy of standards

Standards for coding style MUST be obtained from the following hierarchy in the order specified:

  1. Third-party
  2. Language
  3. First-party

Third-party

“Third-party” refers to the third-party software you are using and the corresponding Third-party coding standards. For example, if you are using Django, you MUST use the Django coding style. If any of the following conditions hold then you MUST move to Language:

  1. You are not using third-party software
  2. The third-party software does not specify a coding standard
  3. The coding standard does not specify a rule (for example how to name variables)

Language

“Language” refers to the language you are using and the corresponding language coding standards. For example, if you are using Python, you MUST use the PEP 8 – Style Guide for Python Code. If any of the following conditions hold then you MUST move to First-party:

  1. The language does not specify a coding standard
  2. The coding standard does not specify a rule (for example how to name variables)

First-party

“First-party” refers to the First-party coding standards. These standards are developed by Q-CTRL and exist to specify standards that are not defined in the coding standards of the third-party software or language you are using.

Third-party coding standards

Third-party Style Docstrings Testing Linting
Django Django coding style numpydoc[++] pytest Pylint or Ruff
Protocol Buffers Buf Style Guide N/A N/A buf lint
React Q-CTRL ESLint Config TSDoc Jest, Testing Library, and Playwright ESLint and Prettier
Terraform Terraform Style Guide N/A N/A terraform fmt

Language coding standards

Language Style Docstrings Testing Linting
Cython PEP 8 numpydoc[++] pytest (Pylint, Black, isort) or Ruff
Go Effective Go Godoc go test go vet and Staticcheck
GraphQL GraphQL Rules CommonMark N/A graphql-schema-linter
HTML Prettier N/A Playwright Prettier
JavaScript Q-CTRL ESLint Config JSDoc Jest, Testing Library, and Playwright ESLint and Prettier
Markdown N/A N/A N/A markdownlint
Python PEP 8 numpydoc[++] pytest (Pylint, Black, isort) or Ruff
Rust rustfmt rustdoc cargo test Clippy
TypeScript Q-CTRL ESLint Config TSDoc Jest, Testing Library, and Playwright ESLint and Prettier
YAML Home Assistant YAML Style Guide N/A N/A yamllint

First-party coding standards

Variable naming

Unless prescribed otherwise by the framework or language (as described above), use the following rules when naming variables:

  • Spell variable names out in full using American English spelling (for example optimized_pulse or optimizedPulse and NOT op).
  • For variable names that are more than three words, use an acronym (for example cpmg and NOT carr_purcell_meiboom_gill or carrPurcellMeiboomGill).
  • For variable names that describe how many of an object there are, use <object>_count or <object>Count (for example pulse_count or pulseCount and NOT number_of_pulses, numberOfPulses, pulses_count, or pulsesCount).
  • Capitalize only the first letter of acronyms in camelCase or PascalCase names (for example QctrlApiException or tensorPwc and NOT QCTRLAPIException or tensorPWC).

OIDC authentication provider

We currently use Keycloak for our OpenId Connect (OIDC) authentication. As OIDC is a standard for authentication and Keycloak is only our current provider all variables required for use related to OIDC should be prefixed with OIDC_. Avoid KEYCLOAK_ unless you feel there is a valid reason for bringing that prefix back into use, in which case bring it up for discussion.

Docstrings

numpydoc

The numpydoc standard is unclear, unopinionated, or inconsistent in a small number of cases. We therefore adopt the following additional standards.

  • For docstrings that fit on a single line, the opening and closing triple quotes should be on the same line as the content, as follows:

    """An example docstring that fits on a single line."""
    

    For docstrings that span multiple lines, place the opening and closing triple quotes of on their own lines, with no blank lines separating them from the contents, as follows:

    """
    An example docstring.
    
    Optional additional paragraphs that go into more detail.
    """
    
  • Use single backticks when referring to a module, function, class, method, parameter, variable, or attribute thereof; otherwise use double backticks (for example `np.array`, `int`, `parameter_1`, `CustomClass.attribute`, `CustomClass.method`, ` value_1*value_2 , function().result , or List[int] `). Do not use backticks for literals such as 3.2, “string”, True, or None.
  • We adopt the following on top of numpydoc’s style for parameter types, as is too simple for some complex types:

    • We use Python 3.9 (or later) syntax to represent lists or tuples.
    • If a parameter has requirements on its shape or data type, we include that information in parentheses.
    • The word “optional” at the end of a type indicates that a parameter has a default value. If a parameter is nullable we add “or None” to its type.

    Below are a few examples of how we might represent some types.

    hamiltonian : Pwc or SparsePwc
    noise_operators : list[np.ndarray or Tensor or Stf] or None, optional
    lindblad_terms : list[tuple[float, np.ndarray or sp.sparse.spmatrix]]
    cost : Tensor(scalar, real)
    verbose : bool, optional
    sample_times : np.ndarray(1D, real)