Table of Contents

Using Code Formatters

Brock Schmutzler Updated by Brock Schmutzler

This article contains some quick tips for to use JuliaFormatter, black, and styler to format code written in Julia, Python, and R (respectively). In particular, we discuss how to use these formatting packages in conjunction with Jupytext and nbQA to easily format code in the cells of a Jupyter Notebook. Using automatic code formatters can save a lot of time while making your code easy to read and maintain.

Before using automatically formatting code, make sure to get consent from your faculty partner and work with them to settle on a particular formatting configuration. If faculty would generally like to use a code formatter but not for certain parts of their code, you can insert "magic comments" that tell a formatter to skips those parts (details in sections below).
All formatting packages discussed in this article are installed on the Ubuntu 22.04 + JupyterLab + RStudio stack, which comes with eCornell's JupyterLab Starter Pack.

Julia

This section covers the tools for automatically formatting Julia code using JuliaFormatter and jupytext.

Installation

To install the JuliaFormatter.jl package:

  1. Open a terminal in Codio by selecting Tools > Terminal from the top menu
  2. At the ~/workspace$ prompt, execute julia to start a Julia session
  3. At the julia> prompt, press the ] key to start the package manager
  4. At the pkg> prompt, execute add JuliaFormatter to install the package

If you are formatting Julia code in a Jupyter Notebook, also install Jupytext:

  1. Open a terminal in Codio by selecting Tools > Terminal from the top menu
  2. At the ~/workspace$ prompt, execute pip install --upgrade pip to upgrade pip
  3. At the ~/workspace$ prompt, execute pip install jupytext
Usage

The JuliaFormatter.jl package can be used to format Julia code from a Julia console:

julia> using JuliaFormatter

# Recursively formats all Julia files in the current directory
julia> format(".")

# Formats an individual file
julia> format_file("foo.jl")

# Formats a string (contents of a Julia file)
julia> format_text(str)

Jupytext and JuliaFormatter can be used together to format Julia code in a Jupyter Notebook. To reformat a notebook.ipynb file with Julia code, you can run the following terminal command from the ~/workspace directory in Codio:

jupytext --pipe "julia -e 'using JuliaFormatter; format_file(ARGS[1])' {}" notebook.ipynb

See Jupytext CLI for other jupytext commands that you may find useful.
Configuration

To configure JuliaFormatter formatting options, create a .JuliaFormatter.toml file (read the JuliaFormatter documentation for all the possible formatting options). For example, consider

# This is a configuration file that specifies how `JuliaFormatter` behaves.

# Three coding styles besides the default style
#style = "yas" # uncomment to use this style
#style = "blue" # uncomment to use this style
#style = "sciml" # uncomment to use this style

# Formatting options (overrides default style or style specified above)
margin = 79 # default is 92
trailing_comma = true # default is true
trailing_zero = true # default is true
always_for_in = true # default is false
for_in_replacement = "∈" # default is "in"
whitespace_typedefs = true # default is false
remove_extra_newlines = true # default is false
import_to_using = true # default is false
short_to_long_function_def = true # default is false
format_docstrings = true # default is false

Put your .JuliaFormatter.toml file in the ~/workspace directory of Codio:

Example of file that configures options for JuliaFormatter

Example

As a concrete example of how this works, consider a Julia notebook with the following two cells:

First cell in need of reformatting
Second cell in need of reformatting

From the ~/workspace directory terminal, running the command

jupytext --pipe "julia -e 'using JuliaFormatter; format_file(ARGS[1])' {}" CHEME-132-Module-3-WorkedExample.ipynb

produces the following output for the first cell (first image) and second cell (second and third images):

First cell with reformatted Julia code
Second cell with reformatted Julia code (first image)
Second cell with reformatted Julia code (second image)
You can use the magic comments #! format: off and #! format: on to tell JuliaFormatter to ignore parts of the code, as described in the documentation on skipping formatting.

Python

This section discusses how to automatically format Python code using black, isort, blacken-docs, and nbqa.

Installation

To install the packages black, blacken-docs, isort, and nbQA:

  1. Open a terminal in Codio by selecting Tools > Terminal from the top menu
  2. At the ~/workspace$ prompt, execute pip install --upgrade pip to upgrade pip
  3. At the ~/workspace$ prompt, execute pip install black blacken-docs isort nbqa
You only need to install nbqa if you are formatting Python code in a Jupyter Notebook (you could also use the Jupytext CLI).
Usage

You can use the Python packages black and isort to quickly format Python code and import statements. Black is an "opinionated" formatter in the following sense:

Black aims for consistency, generality, readability and reducing git diffs. Similar language constructs are formatted with similar rules. Style configuration options are deliberately limited and rarely added. Previous formatting is taken into account as little as possible, with rare exceptions like the magic trailing comma. The coding style used by Black can be viewed as a strict subset of PEP 8.

Isort is used for sorting import statements alphabetically and separated them into sections by type. You can run black and isort from a Python console:

>>> black file.py
>>> isort file.py

You can use nbQA with the Python packages black, blacken-docs, and isort to quickly format Python code in Jupyter Notebooks according to the Black code style. Here's a quick list of the tools and their uses:

  • black formats Python code
  • blacken-docs uses the Black code style to format Python code in Markdown cells of a Jupyter Notebook
  • isort sorts import statements
  • nbqa ensures black, blacken-docs, and isort work seamlessly with Jupyter Notebooks

To format Python code in a Jupyter Notebook, use the commands above together with the command nbqa from the terminal in the directory that contains the notebook file. For example, if you have ~/workspace/file.ipynb , then you would run the following commands from the ~/workspace$ command-line prompt:

nbqa black file.ipynb
nbqa blacken-docs file.ipynb --nbqa-md
nbqa isort file.ipynb

Add the flag --nbqa-diff to see what changes would be made to file.ipynb if you were to run one of the formatting commands. For example, executing nbqa black file.ipynb --nbqa-diff would show you the changes that would be made to file.ipynb if you run the command nbqa black file.ipynb.
Configuration

To ensure that black and isort are compatible (so that their formatting preferences do not overwrite each other), create a workspace/pyproject.toml file with the following contents:

[tool.isort]
profile = "black"

Specify "black" as the profile for isort

You can also specify preferences for black in pyproject.toml (this is not necessary):

[tool.black]
line-length = 79
target-version = ["py311"]

The above specifications configure black to use a maximum line length of 79 characters (instead of the default 88) and to provide support for Python 3.11.x code. In general, you probably won't need (or want) to configure Black any more than changing the line length and version of Python.

To preserve intentional multi-line formatting, use the magic trailing comma. If you want Black to ignore parts of the code, you can use the inline magic comment # fmt: skip to ignore a line of code or the comments # fmt: off and # fmt: on to ignore code blocks, as described in the documentation on ignoring sections.

After you have created a suitable pyproject.toml file, you are ready to use black and isort to format your notebook.

Example

Consider the following Building_a_Fault_Tree.ipynb file in need of formatting:

First image of example notebook to reformat
Second image of example notebook to reformat
Third image of example notebook to reformat

In the step-by-step procedure below, we will use this notebook to illustrate each step.

  1. Execute nbqa isort notebook.ipynb --float-to-top to use nbqa and isort to sort all the import statements in your notebook and "float" them up to the first code cell (remove --float-to-top to keep all the import statements in their original code cells)
    Run isort on your notebook
    Result of running isort
  2. Execute nbqa black notebook.ipynb to format the notebook in the Black code style
    Run black on your notebook
  3. Create a separate cell at the top of your notebook that only contains the import statements. Inspect the rest your reformatted notebook and make any further changes by hand (e.g., removing blank lines)
    First image of reformatted notebook using isort and black
    Second image of reformatted notebook using isort and black
    Third image of reformatted notebook using isort and black

When using isort to sort import statements, use the inline magic comment # isort:skip if you want isort to ignore certain lines. This is necessary when the order of import statements is critical.

The steps below show an example where the path /home/codio/workspace/.modules must be appended before the from helper import * statement in order for the helper module to be found in the .modules folder. In this case, the inline magic comment # isort:skip tells isort to ignore the two lines whose order matters.

  1. Original import statement cell before applying black or isort
    Import cell before formatting code with Black or sorting imports with isort
  2. black formats the code but does not change order of imports
    Import cell after formatting code with Black
  3. isort changes the order of import statements and breaks from helper import *
    Import cell after running isort
  4. Manually correcting and rerunning isort with # isort:skip preserves the necessary order
    Import cell after correction and running isort with # isort:skip
  5. Rerunning black only changes horizontal spacing of second # isort:skip comment
    Import cell after rerunning Black after isort

R

In this section, we walk through the process of automatically formatting R code using styler and jupytext.

Installation

To install the styler package:

  1. Open a terminal in Codio by selecting Tools > Terminal from the top menu
  2. At the ~/workspace$ prompt, execute R to start an R session
  3. At the > prompt, execute install.packages("styler")
The styler package is bundled with the tidyverse collection, so install.packages("tidyverse") would also install styler (along with many other R packages).

If you want to format R code in a Jupyter Notebook, install Jupytext:

  1. Open a terminal in Codio by selecting Tools > Terminal from the top menu
  2. At the ~/workspace$ prompt, execute pip install --upgrade pip to upgrade pip
  3. At the ~/workspace$ prompt, execute pip install jupytext
Usage

You can use the R library styler to quickly format R code according to the tidyverse style guide. To get started, you can format R code from an R console:

# Style .qmd, .R, .Rmd, .Rmarkdown, .Rnw, and .Rprofile files
> style_file("file_name")

# Style all files in a directory
> style_dir("directory_path")

# Style all source files of an R package
> style_package("package_name")

Configuration

You can use the magic comments # style: off and # style: on to tell styler skip parts of your code, as described in the documentation on ignoring certain lines. You can also control the level of invasiveness and set various configuration options (e.g., number of spaces to indent), but the defaults should be good for general use.

Example

Jupytext and styler can be used together to format R code in a Jupyter Notebook.

See Jupytext CLI for jupytext commands that you could use with the styler package, much like jupytext and JuliaFormatter.

Consider the following notebook with R code in need of reformatting:

R code that needs reformatting in a Jupyter Notebook

  1. In Preview mode, pair your notebook.ipynb with an R Markdown file by going to the the JupyterLab menu and selecting File > Jupytext > Pair Notebook with R Markdown
    Use Jupytext to pair notebook.ipynb with an R Markdown file
  2. Pairing notebook.ipynb creates a notebook.Rmd file that is synchronized with notebook.ipynb (any changes to one file be automatically propagated to the other)
  3. Open a terminal and use styler to reformat the notebook.Rmd file with the following commands:
    1. $ R
    2. > library(styler)
    3. > style_file("notebook.Rmd")
      Use styler to reformat the paired R Markdown file
  4. In Preview mode, review the synchronized changes in notebook.ipynb
    Review formatting changes in Preview mode

How did we do?

Using the JupyterLab Starter Pack

Using the RStudio Starter Pack

Contact