Hacker News new | ask | show | jobs
by eliben 4099 days ago
yapf starts making tons of sense after you've used similar tools in other languages. The chief two examples are "go fmt" and clang-format. The former goes without saying - formatting is enforced in Go.

The latter is widely used to format C, C++ (and even JS and Java) code. Many projects these days require all code to be clang-format'ed and even enforce it in commit hooks and such.

After working on such projects for a while, you get so used to the convenience of an auto-formatting tool, that you want it in all languages you code in. It's extremely useful to be able to just type a bunch of code quickly into the editor, copy-pasting, renaming, and know that the tool will nicely format it for you. Another advantage is that the whole code in a projects starts being and looking very consistent, which is important. Holy wars about brace placement and indentation just disappear.

So yapf is essentially that, for Python.

1 comments

FWIW, at Yelp we built and open sourced pre-commit (http://pre-commit.com/) that runs a bunch of hooks on git commits. One of the most commonly used hooks is `autopep8 -i` which will automatically formats code on commit.

As yapf documentation has pointed out, pep8 is vague about certain things (i.e. indention). Yelp prefers an indention style where multiple arguments are broken up 1 per line and has a pre-commit hook to automatically enforce that. yapf is also opinionated about indentation, preferring vertical alignment. I've run it on an open source project to illustrated the differences (YelpDent vs yapf indent):

     def remove_user_data(dryrun=False):
         if platform.system() == 'Darwin':
    -        data_home = os.path.join(
    -            os.path.expanduser('~'),
    -            'Library',
    -            'autojump')
    +        data_home = os.path.join(os.path.expanduser('~'), 'Library',
    +                                 'autojump')
        elif platform.system() == 'Windows':
            data_home = os.path.join(os.getenv('APPDATA'), 'autojump')
        else:
    -        data_home = os.getenv(
    -            'XDG_DATA_HOME',
    -            os.path.join(
    -                os.path.expanduser('~'),
    -                '.local',
    -                'share',
    -                'autojump'))
    +        data_home = os.getenv('XDG_DATA_HOME',
    +                              os.path.join(os.path.expanduser('~'), '.local',
    +                                           'share', 'autojump'))
We're actually working on a heuristic that can signal yapf to break arguments to one per line, and do the same for data structures (think a dict initialization).

Ultimately, we'd like to have these things configurable via the style settings of yapf, so multiple detailed styles can be selected.

Patches welcome :)

If you'd like my suggestion. I've been quite annoyed with some of the "odd" or "non-consistent" ways for splitting long lines onto multiple lines (either on definitions, or plain calls to functions). Eventually, I did come up with a consistent way to do so. Have a look at below:

    def OtherLongFunctionName(One,
      Two,
      Three
    ):
        print "Does stuff"
    
    def MyFunction(Param1,
      OtherParam,
      FooParam,
      EtcParam
    ):
        if ((Param1 * 1000) > 5000 &&
          OtherParam is not None &&
          len(FooParam) > 50
        ):
            new_instance_dict = {
              "TestingFoo": Param1,
              "NewFoo": OtherParam,
              "LongFooBar": FooParam,
            }
    
        recursive = MyFunction(
          OtherLongFunctionName(
            Param1,
            OtherParam,
            FooParam
          )
        )
It doesn't comply to PEP8 due to the indentation of nested params and stuff on the new lines. PEP8 apparently wants them aligned with the opening/starting bracket. This looks horrible, and just right-aligns all your code into little columns. And doesn't work very well with nested function calls.
Please don't make it configurable, because it will mean there is no longer "a" YAPF standard. Also look at Pycharm reformat tool, it would be a shame if both couldn't be used in the same versionned project.