# Code Style

# Black formatting

Prefect's code is formatted using the black style. This style is checked in a CI step, and merges to master are prevented if code does not conform.

To apply black to your code, run black from the root Prefect directory:

cd prefect
black .

Please note that black requires Python 3.6+ (though Prefect does not).

Formatting can be easy to forget when developing, so you may choose to install a pre-push hook for black, as follows:

pip install pre-commit # installs pre-commit package
cd prefect/ # make sure you are in the root directory of the prefect repo
pre-commit install --hook-type pre-push # creates necessary git hook files

There is already a pre-commit config file contained in the repo that creates the pre-push hook for black. Once installed, you won't be allowed to git push without passing black.

In addition, a number of extensions are available for popular editors that will automatically apply black to your code.

# Docstrings

Prefect auto-generates API documentation from docstrings by compiling them to Markdown. In order for docstrings to compile correctly, please follow these rules:

Docstring Formatting

  • All documentation about class initialization should go into the class docstring, not the __init__ method docstring.
  • Any references to "code" or variable names should be surrounded by backticks so it will be properly formatted in Markdown.
  • Arguments are indicated by the word Args: followed by a Markdown list that indicates each argument's name, type, and description:
    Args:
        - x (int): a number that provides the initial value.
    
  • The return value is indicated by the word Returns: followed by a Markdown list that indicates the return value's type and description. Note that a list is required even though there is only a single return type:

    Returns:
        - int: a number representing the output
    
  • Any errors raised by a function are indicated by the word Raises: followed by a Markdown list that indicates each exception's type and description:

    Raises:
        - ValueError: if the input is zero or negative
    

Here is an example of a fully-documented module:

"""
This docstring describes this module.
"""

def function(x: List[str] = None) -> int:
    """
    This is a function docstring.

    Args:
        - x (List[str], optional): any information about x

    Returns:
        - int: any details about the return value
    """
    pass


class Class:
    """
    This is the class docstring, which also describes its `__init__()` constructor.

    Note that __init__ does not require an annotation for `self` or for the return value
    (which is always `None`), as long as at least one other argument is typed.

    Args:
    - x (int): a number

    """

    def __init__(self, x: int):
        pass

    def method(self, x: int, y: float, z: str = None) -> int:
        """
        Something interesting about what this method does.

        Args:
            - x (int): any information about `x`
            - y (float): additional info about `y`
            - z (str, optional): defaults to `None`; note that codeblocks are not currently
                supported within arg docs

        Additional information if desired; note that backticks for code formatting
        is encouraged within argument descriptions, but should *not* be used in
        the argument type.  Also, all other documentation can contain Markdown.

        Returns:
            - int: details about the return value

        Raises:
            - ValueError: if `x == 0`
        """
        pass

# Mypy typing

Prefect's code is statically-typed using mypy. Type checking is validated as a CI step, and merges to master are prevented if code does not pass type checks.

While we would prefer for all of Prefect's code to be typed, that creates an undesirable friction for new contributors. Therefore, mypy is only required for "important" code (generally, files in the core/ and engine/ directories), but encouraged elsewhere. Test files are never checked for typing. To run mypy locally:

cd prefect
mypy src

As a general rule, mypy typing requires all function arguments and return values to be annotated.