pythonpython-black

What to do when your formatter and your linter are fighting


I've been writing a decorator in Python:

def dictionary_updater(key: str) -> Callable[[FieldStringer], PayloadSetter]:
    """Convert string-converter to dictionary modifier.
    """
    # Create the actual decorator method and return it
    def inner(func: FieldStringer) -> PayloadSetter:
        # Create the method that should actually be called when the decorated function
        # is invoked
        def with_dict(self, payload: Payload) -> None:
            payload[key] = func(self)

        return with_dict

    return inner

The issue I'm having is that black will try to put an empty line after the docstring, I assume because the first line of code is a function definition. However, pydocstyle will complain about this because there's not supposed to be an empty line between the docstring and the function body.

I've tried disabling the rule for each system, respectively, but because it's an empty line, both tools appear to be ignoring it. Furthermore, I can't just disable the tools themselves or modify their rules because they're part of a CI/CD pipeline I have no control over. I suppose I could disable one tool or the other for the entire file, but I'd rather not do that either, as that defeats the purpose of having the tools in the first place.

Does anyone know how to fix this issue?


Solution

  • It turns out the issue was that I had commented the wrong line. Originally, I was doing this:

    def dictionary_updater(key: str) -> Callable[[FieldStringer], PayloadSetter]:
        """Convert string-converter to dictionary modifier.
        """
        # fmt: skip
        # Create the actual decorator method and return it
        def inner(func: FieldStringer) -> PayloadSetter:
            # Create the method that should actually be called when the decorated function
            # is invoked
            def with_dict(self, payload: Payload) -> None:
                payload[key] = func(self)
    
            return with_dict
    
        return inner
    

    which wasn't working. After a little thought, I realized that black would be adding the line from the previous line, so I had to put my comment there. I amended my code to look like this:

    def dictionary_updater(key: str) -> Callable[[FieldStringer], PayloadSetter]:
        """Convert string-converter to dictionary modifier.
        """  # fmt: skip
        # Create the actual decorator method and return it
        def inner(func: FieldStringer) -> PayloadSetter:
            # Create the method that should actually be called when the decorated function
            # is invoked
            def with_dict(self, payload: Payload) -> None:
                payload[key] = func(self)
    
            return with_dict
    
        return inner
    

    and now everything works. That being said, these sorts of problems are an excellent argument against excessive linting, IMHO.