# Using hacking

## Introduction

hacking is a set of flake8 plugins that test and enforce the OpenStack StyleGuide

Hacking pins its dependencies, as a new release of some dependency can break hacking based gating jobs. This is because new versions of dependencies can introduce new rules, or make existing rules stricter.

## Installation

hacking is available from pypi, so just run:

    pip install hacking

This will install specific versions of `flake8` with the `hacking`, `pep8`, `mccabe` and `pyflakes` plugins.

## Origin

Hacking started its life out as a text file in Nova’s first commit. It was initially based on the Google Python Style Guide, and over time more OpenStack specific rules were added. Hacking serves several purposes:

1. Agree on a common style guide so reviews don’t get bogged down on style nit picks. (example: docstring guidelines)

2. Make code written by many different authors easier to read by making the style more uniform. (example: unix vs windows newlines)

3. Call out dangerous patterns and avoid them. (example: shadowing built-in or reserved words)

Initially the hacking style guide was enforced manually by reviewers, but this was a big waste of time so hacking, the tool, was born to automate the process and remove the extra burden from human reviewers.

## Versioning

hacking uses the `major.minor.maintenance` release notation, where maintenance releases cannot contain new checks. This way projects can gate on hacking by pinning on the `major.minor` number while accepting maintenance updates without being concerned that a new version will break the gate with a new check.

For example a project can depend on `hacking>=0.10.0,<0.11.0`, and can know that `0.10.1` will not fail in places where `0.10.0` passed.

## Adding additional checks

Each check is a pep8 plugin so read

- https://github.com/jcrocholl/pep8/blob/master/docs/developer.rst#contribute

The focus of new or changed rules should be to do one of the following

- Substantially increase the reviewability of the code (eg: H301, H303) as they make it easy to understand where symbols come from)

- Catch a common programming error that may arise in the future (H201)

- Prevent a situation that would 100% of the time be -1ed by developers (H903)

But, as always, remember that these are Guidelines. Treat them as such. There are always times for exceptions. All new rules should support noqa.

If a check needs to be staged in, or it does not apply to every project or its branch, it can be added as off by default.

### Requirements

- The check must already have community support. We do not want to dictate style, only enforce it.

- The canonical source of the OpenStack Style Guidelines is StyleGuide, and hacking just enforces them; so when adding a new check, it must be in `HACKING.rst`

- False negatives are ok, but false positives are not

- Cannot be project specific, project specific checks should be Local Checks

- Include extensive tests

- Registered as entry_points in `setup.cfg`

- Error code must be in the relevant `Hxxx` group

- The check should not attempt to import modules from the code being checked. Importing random modules, has caused all kinds of trouble for us in the past.

## Enabling off-by-default checks

Some of the available checks are disabled by default. These checks are:

- [H106] Don’t put vim configuration in source files.

- [H203] Use assertIs(Not)None to check for None.

- [H204] Use assert(Not)Equal to check for equality.

- [H205] Use assert(Greater|Less)(Equal) for comparison.

- [H210] Require ‘autospec’, ‘spec’, or ‘spec_set’ in mock.patch/mock.patch.object calls

- [H904] Delay string interpolations at logging calls.

To enable these checks, edit the `flake8` section of the `tox.ini` file. For example to enable H106 and H203:

    [flake8]
    enable-extensions = H106,H203

## Local Checks

hacking supports having local changes in a source tree. They need to be registered individually in tox.ini:

Add to tox.ini a new section flake8:local-plugins and list each plugin with its entry-point. Additionally, you can add the path to the files containing the plugins so that the repository does not need to be installed with the paths directive.

    [flake8:local-plugins]
    extension =
      N307 = checks:import_no_db_in_virt
      N325 = checks:CheckForStrUnicodeExc
    paths =
      ./nova/hacking

The plugins, in the example above they live in nova/hacking/checks.py, need to annotate all functions with @core.flake8ext

    from hacking import core
    ...
    @core.flake8ext
    def import_no_db_in_virt(logical_line, filename):
        ...

    class CheckForStrUnicodeExc(BaseASTChecker):
       name = "check_for_str_unicode_exc"
       version = "1.0"
       ...

Further details are part of the flake8 documentation.

this page last updated: 2023-08-22 10:18:51

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.

found an error? report a bug