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

Feature align argument assignment #1031

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

lizawang
Copy link

@lizawang lizawang commented Oct 3, 2022

Hello all yapf founders!

I have some new features I want to share with the yapf community.
This is also a response to issue #194 and issue #346.

The alignment feature added is referred to the yapf function _AlignTrailingComments(final_lines).

The knobs

The main functions for all the knobs are added in reformatter.py.

knob: ALIGN_ARGUMENT_ASSIGNMENT

This is an option to align the assignment operators of each block inside the argument list of a function call or a function definition.

  • The condition : it is only effective if all arguments inside the argument list are placed on separate lines.

  • The case when the typed argument name is too long that it has newlines, we can increase the column limit, otherwise it will be aligned with the last line of the unwrapped typed argument name that has the assignment operator:

    def __init__(
        self,
        title: Optional[ str ],
        diffs: Collection[ BinaryDiff ]       = (),
        charset: Union[ Type[ AsciiCharset ],
                        Type[ LineCharset ] ] = AsciiCharset,
        preprocess: Callable[ [ str ], str ]  = identity,
        # TODO(somebody): Make this a Literal type.
        justify: str = 'rjust' ):
      pass
    
  • New block of arguments starts with new alignment. There are 3 cases featured as an indication for new alignment block:

    • Each nested argument list inside with different indentation depth is a new block:
      nested_arglist = test(
          a = fun(
              var_first  = 0,
              var_second = '',
              var_third  = 1,
              var_fourth = None,
              var_fifth  = None ),
          abc = 1,
          d   = 2 )
      
    • A comment line inside a argument list of same level creates a new block:
      def get_dataframes_from_excel(
          self,
          *,
          info_sheet  = 0,
          skip_sheets = None,
          # comment
          df_sheet_names = [],
          rstrip_str     = True,
          **read_excel_kwargs ):
        pass
      
    • An object(a list/a dictionary/an argument list/ a set/a function call, etc.) with its items in newlines in between creates a new block inside the argument list of the same level:
      arglist = test(
          var_first  = 0,
          var_second = '',
          var_dict   = {
              "key_1" : '',
              "key_2" : 2,
              "key_3" : True,
          },
          var_third     = 1,
          var_very_long = None )
      
      
      arglist = test(
          var_first  = 0,
          var_second = '',
          get_dataframe_from_excel_sheet(
              filepath, usecols = [ 0 ], header = None, dtype = str ),
          var_third     = 1,
          var_very_long = None )
      

knob: NEW_ALIGNMENT_AFTER_COMMENTLINE

This option is made under the consideration that some programmers may prefer to remain the alignment with comment lines inside.

  • If it is set False, a comment line in between won't create a new alignment block. Entries before and after the comment line/lines will align with their assignment operators.

Preparations

To make the alignment functions possible, some other changes are made to other files.

  • subtype_assigner.py: a change is made to include the subtype TYPED_NAME_ARG_LIST to all tokens inside typed argument name. This is to recognize all tokens before '=' of very long typed name in arguments with typed names, e.g., a typed argument as below:

    charset: Union[ Type[ AsciiCharset ], Type[ LineCharset ] ] = AsciiCharset,

  • format_token.py: necessary boolean functions are added, is_argassign, is_argname, is_argname_start.

Finally

In the end, the knobs are added into the style.py and tests for each one are also updated in yapftests folder.

  • style.py: all the 2 knobs are set to be False by default.
  • Unitests are added into format_token_test.py, subtype_assigner_test.py and reformatter_basic_test.py.



@gsmethells
Copy link

🙏🏻

@JackLilhammers
Copy link

The lack of the features you've implemented are the reason why I don't use formatters. Thank you!

@ufukty
Copy link

ufukty commented Jan 3, 2023

I left a comment on the original issue saying hope it gets attention of reviewers. It is frustrating to see no reviewers picked those PRs up yet for 3 months.

@c0nfleis
Copy link

Bumping this! Love this feature, really want to use it!

@JackLilhammers
Copy link

@lizawang Since the devs seem quite slow to merge these PRs, would you make a branch in your fork that integrates them all or would you assist me in doing so?
I already tried, but not knowing the inner workings of yapf I don't really know how to solve the merge conflicts that happen when I try to merge 2 or more of your PR branches

@lizawang
Copy link
Author

Hello JackLilhammers, I'm glad that you like the features. If you want to use all alignment features, you can go to my forked yapf and use the branch called "feature_align_assignment_and_dictColon" which has alignment features for both assignments (including argument assignment) and colons in dictionaries. You can also use the branch "nemetris" which in addition has some fixes for inline comment alignment.

@KevinDHall
Copy link

@lizawang I downloaded your "feature_align_assignment_and_dictColon" branch. I'm trying to build your branched version of yapf so that I can use it instead on my Windows-based machine. I've executed "python setup.py build", but I don't see a yapf.exe built. Do you know how I can build yapf.exe and then install it locally -- or a guide that shows how this is done for python projects in general? Many thanks!

@jpcurti
Copy link

jpcurti commented Feb 28, 2023

Bump! This has been long long wanted from many users. Thanks!

@uprokevin
Copy link

thank you !

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

Successfully merging this pull request may close these issues.

8 participants