Skip to content

Strange formatting of fluent interfaceΒ #571

Open

Description

@WouldYouKindly

Operating system: Mac
Python version: 3.7
Black version: 18.9b0
Does also happen on master:

Following on https://twitter.com/llanga/status/1052631100290420736

I have a code which uses yarl.URL

a = str(
    my_very_very_very_long_url_name
    .with_user(and_very_long_username)
    .with_password(and_very_long_password)
)

Black formats it like this

a = str(
    my_very_very_very_long_url_name.with_user(and_very_long_username).with_password(
        and_very_long_password
    )
)

I understand that first call is not on a new line because of reasons, but the rest still looks quite odd, especially considering that when there are three calls in the chain, Black produces

a = str(
    my_very_very_very_long_url_name.with_user(and_very_long_username)
    .with_user(and_very_long_username)
    .with_password(and_very_long_password)
)

Activity

  1. added
    T: styleWhat do we want Blackened code to look like?
    on Feb 14, 2019
  2. max-sixty commented on Mar 1, 2019

    @max-sixty

    Forgive me for using this as the fluent questions thread, but another case:

    With a single call

    def x():
        base_ds["security_score_filtered"] = base_ds["security_score_risk_adj"].where(
            base_ds["is_share_price_valid"]
            & base_ds["is_market_cap_valid"]
            & base_ds["is_liquid"]
        )

    With two calls

    def x():
        base_ds["security_score_filtered"] = (
            base_ds["security_score_risk_adj"]
            .where(
                base_ds["is_share_price_valid"]
                & base_ds["is_market_cap_valid"]
                & base_ds["is_liquid"]
            )
            .sum()  # <- new line here (only change)
        )

    Why the switch of the first line between the two?

    I would generally prefer the second format even without the second call (though the question stands independent of my opinion)

  3. max-sixty commented on Mar 21, 2019

    @max-sixty

    Adding another here, as a (hopefully) helpful additional case:

    From:

        df = (
            gbq
            .read_gbq(query, project="sixty-capital-prod")
            .sort_values("factset_entity_id")
        )

    To:

        df = gbq.read_gbq(query, project="sixty-capital-prod").sort_values(
            "factset_entity_id"
        )
  4. max-sixty commented on May 30, 2019

    @max-sixty

    And another:

    Looks good:

                    completion_time = (
                        a.read_namespaced_job(job.metadata.name, namespace="default")
                        .status()
                        .completion_time()
                    )

    Now without the () on the last two lines after status & completion_time :

                    completion_time = a.read_namespaced_job(
                        job.metadata.name, namespace="default"
                    ).status.completion_time
  5. MrkGrgsn commented on Mar 10, 2020

    @MrkGrgsn

    I would prefer that black applies the fluent style across more cases of chained calls and attribute accesses, such as those examples provided above, even if it does use a few more lines. Consistency between these similar multi-line expressions is more valuable to me than removing a few extra lines.

  6. vedal commented on Feb 11, 2021

    @vedal

    Is this possible to define flhent interface in black settings?

  7. peterHoburg commented on Oct 20, 2021

    @peterHoburg

    Related to my comment: #2279 (comment)

  8. added
    S: needs discussionNeeds further hashing out before ready for implementation (on desirability, feasibility, etc.)
    on Jan 31, 2022
  9. felix-hilden commented on Jan 31, 2022

    @felix-hilden
    Collaborator

    Since there are no maintainer comments yet on this issue, I'll echo the points already raised: I'd also like for Black to format fluent interfaces with or without initial parens consistently:

    def func():
        (
            thing("argument-1")
            .thing("argument-2")
            .thing("argument-3")
            .thing("argument-4")
            .thing("argument-5")
            .thing("argument-6")
            .thing("argument-7")
            .thing("argument-8")
            .thing("argument-9")
        )

    adding the parens rather than splitting a single call if the line is too long.

  10. felix-hilden commented on Jan 31, 2022

    @felix-hilden
    Collaborator

    Here's a more complete set of variations I'd expect to behave similarly: playground

    • Regardless of the presence of initial surrounding parentheses, if the line is too long and there is a call chain we should add parens and split on method/attribute access (dots)
    • Whether or not the expression is an assignment should have no effect on the call chain formatting
    • Whether or not the calls contain any arguments should also not have an effect on the formatting beyond splitting further if the call itself is too long, unless:
    • Having magic trailing commas should explode the calls as normal

    In the example playground, I find that the cases with no assignment and no initial parens are formatted against my expectations.

  11. PeterJCLaw commented on Jan 31, 2022

    @PeterJCLaw

    From #571 (comment) I suggest we add to the list:

    • Whether or not a member access is a call should have no effect on the call chain formatting
  12. felix-hilden commented on Jan 31, 2022

    @felix-hilden
    Collaborator

    And in that case, #510 is very relevant, if not duplicate. But I'll leave it open for now.

  13. joshdunnlime commented on Mar 18, 2023

    @joshdunnlime

    Anything here?

  14. joaomacalos commented on May 1, 2023

    @joaomacalos

    It would indeed be much appreciated if the formatting of fluent interfaces were more consistent. The examples posted by @max-sixty above are very descriptive of the issue.

    With method chaining is often better for readability to have more lines but every method in the chain being called in a new line

  15. vmgustavo commented on Jul 31, 2023

    @vmgustavo

    anything here? this is currently the only thing that is holding me back from using black

  16. JelleZijlstra commented on Jul 31, 2023

    @JelleZijlstra
    Collaborator

    Please write a PR to fix this issue instead of sending unproductive comments.

  17. joaomacalos commented on Aug 2, 2023

    @joaomacalos

    @vmgustavo I'm using # fmt : skip after the closing parenthesis of my fluent chains to keep my formatting when black breaks it.

  18. ion-elgreco commented on Aug 10, 2023

    @ion-elgreco

    @JelleZijlstra is it possible to provide custom method chains? So, this issue gets avoided, or is skipping format the only option here?

  19. mo2menelzeiny commented on Mar 26, 2024

    @mo2menelzeiny

    can we disable this with a flag?

  20. leotrs commented on Nov 24, 2024

    @leotrs

    Any comments from a maintainer? This feature would benefit the scientific Python community greatly since pandas encourages method chaining so much.

  21. tijlk commented on Nov 25, 2024

    @tijlk

    I'm using a lot of PySpark, and the following

    retail_accounts_with_segment_df = (
        retail_accounts_df
        .withColumn("kim_segment_cd", f.lit("not applicable"))
        .withColumn("sbi_id", f.lit("not applicable"))
    )
    

    annoyingly gets formatted by black as:

    retail_accounts_with_segment_df = retail_accounts_df.withColumn(
        "kim_segment_cd", f.lit("not applicable")
    ).withColumn("sbi_id", f.lit("not applicable"))
    

    which is way less readable. I know you're looking for PR's, @JelleZijlstra , but not everyone is in the open source community business. Comments like this are just the users of these open source packages hoping to influence the prioritisation a little bit.

  22. hauntsaninja commented on Nov 26, 2024

    @hauntsaninja
    Collaborator

    not everyone is in the open source community business. Comments like this are just the users of these open source packages hoping to influence the prioritisation a little bit.

    There is no "business" and there is no "prioritisation". There are only PRs. Everyone here is a volunteer.

    I'm locking this issue to prevent more unproductive notifications for the many people interested in this issue. PRs are still welcome!

  23. locked as off topic and limited conversation to collaborators on Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    F: linebreakHow should we split up lines?S: needs discussionNeeds further hashing out before ready for implementation (on desirability, feasibility, etc.)T: styleWhat do we want Blackened code to look like?

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions