Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create sharable configuration presets for Flake8 #1105

Open
asottile opened this issue Apr 3, 2021 · 5 comments
Open

Create sharable configuration presets for Flake8 #1105

asottile opened this issue Apr 3, 2021 · 5 comments

Comments

@asottile
Copy link
Member

asottile commented Apr 3, 2021

In GitLab by @sobolevn on Jul 20, 2019, 02:35

Problem

I am writing quite a complex plugin with lots of configuration options.
Moreover, I also depend on a lot of other plugins as dependencies.

Here's how my configuration looks like for an end user, contents of setup.cfg:

[flake8]
# Base flake8 configuration:
format = wemake
show-source = True
statistics = False
doctests = True
enable-extensions = G

# Plugins:
accept-encodings = utf-8
max-complexity = 6
max-line-length = 80
quotes = single

# Self settings:
max-imports = 14


# Exclude some pydoctest checks globally:
ignore = D100, D104, D401, W504, RST303, RST304

[isort]
# See https://github.com/timothycrosley/isort#multi-line-output-modes
multi_line_output = 3
include_trailing_comma = true
default_section = FIRSTPARTY
# Is the same as 80 in flake8:
line_length = 79

Notice, that I also use flake8-isort and [isort] option, there also might be other sections like [mypy] for flake8-mypy, or [bandit] for flake8-bandit or any other plugins when flake8 acts like a wrapper for other tools.

Currently, we will only talk about [flake8] section, since sadly we are not responsible for other tools.

I do not want my users to copy-paste these settings for several reasons:

  1. They usually make mistakes in this simple action :slight_smile:
  2. I am losing control over the default configuration: I will not be able to change something in their defaults even if I want to
  3. It brings a lot of copy-paste. That's totally inconvenient to use and maintain. One new feature or a bug might force you to go trough all your X project and edit the configuration.

Real world use-cases

Several other linters have this feature. Some of them even consider it as a key feature.

When working for EsLint for example, one can just create a module with a single javascript file and reuse it everywhere.

I propose the same for flake8.
Each user can create its own set of rules for an organisation / set of projects and reuse it without this amount of copy-paste.

Implementation details

Things to point out:

  1. It is not a breaking change, everything so work as-is, no major version bump is required
  2. Without new feature everything should work as-is
  3. New configuration option should take the lowest priority over existing config options

Configuration priority

Higher takes the priority over lower:

  1. CLI flags
  2. setup.cfg / .flake8
  3. New option: --sharable-configuration

Creating new sharable configuration

I guess that reusing entry points here is the best option.

# setup.py
# ...

setup(
   name='my-flake8-config'
   entry_points={
        'flake8.configuration': [
            'myconfig = some.path:ConfigurationClass',
        ],
    },

Then:

  1. Installing: pip install my-flake8-config
  2. Running: flake8 --sharable-configuration=myconfig
  3. Done!

Configuration class API

I am not sure about this. But my vision would be something like:

# some/path.py

class ConfigurationClass(object):
    def sharable_configuration(self):
        return {
           'quotes': 'single',
           # and any other options for `[flake8]` section
        }

Conclusion

This feature allows to transfer configuration in a reliable and clean way, brings no breaking changes, follows the best practices of other lint tools.

Original issue from wemake-python-styleguide: wemake-services/wemake-python-styleguide#164
The same feature I proposed for isort: PyCQA/isort#970

I am super excited to help!

@asottile
Copy link
Member Author

asottile commented Apr 3, 2021

In GitLab by @asottile on Jul 20, 2019, 07:20

The configuration situation in flake8 is already the most complicated part -- it's going to be a hard sell to complicate it even further. There's also the downside in that implicit configuration is reasonably hard to track down.

As for your copy paste, you can reduce at least the following settings:

  • statistics = False - (this is the default)
  • enable_extensions = G - if you control this extension, you can set it to automatically enabled
  • max-line-length = 80 - isn't this the default?

I still think I lean towards explicit configuration here -- even though it means some copy paste and needing something like all-repos to distribute updates

@sigmavirus24
Copy link
Member

I'm surprised I didn't comment on this back on GitLab. Needless to say, @asottile is 100% correct. Config management is already incredibly complicated because of the history of the project. It's been near impossible to deprecate things to make it maintainable (the last attempt was during 3.0).

@sobolevn
Copy link
Member

sobolevn commented Apr 5, 2021

Oh, wow. Great work on moving to GitHub!

And as I was mentioned in this issue:
Right now I am working on an alternative runtime that will support running flake8 plugins and will have this feature.

Example:

extends:
  - typed-linter/recommended
  - flake8/recommended

overrides:
  - glob: some/**/*.py
    checks:
      - name: flake8/W504
        level: none

settings:
  type-engine:
    name: typed-linter/mypy

  reporter:
    name: typed-linter/rich

Link: https://github.com/wemake-services/typed-linter/ (it is private for now, but can be helpful in the future)

I think that this issue can be closed.

@asottile
Copy link
Member Author

asottile commented Apr 5, 2021

I think I'm still going to do this, just not at this time. I'm planning to rework the configuration bits with this in mind

@sigmavirus24
Copy link
Member

I think there might be an easier way to do this @asottile without a giant refactoring being necessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants