-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
ruff formatter: one call per line for chained method calls #8598
Comments
This is something that I also noticed coming from JS where Prettier formats call chains as outlined by you above (except without the outer parentheses). My reasoning for Black/Ruff's call chain formatting is that Black tries to avoid parenthesizing expressions which is more idiomatic (I think): if a + long_call(
arg1,
arg2
):
pass instead of
The way this is implemented is that anything inside of parentheses gets a higher split priority (try to split the content inside parentheses first). I'm not saying that we can't improve the formatting. I'm just trying to explain where I believe black's formatting decision is coming from. |
@MichaReiser Appreciate the context! I completely agree your first example is more readable, so there's some work on defining the goal here. From a very brief consideration, I can only come up with chained method calls as an example of my desired splitting, so perhaps this is a special case? Love to lean on your experience here! |
I would love to see some option to preserve chain methods-call-per-line some_query = (
select(whatever.id, x.something)
.join(x, x.y == whatever.y)
.where(x > 12)
.order_by(whatever.id)
) anyway - ruff rules! |
Hello, first of all, thank you for a great piece of software! Came here to ask for a similar functionality mentioned above: I would like to see chaining methods on new line: It is heavily used in the expression library: (Seq(find_node(labels, polygons_predicate))
.choose(lambda x: x)
.map(parse_points)
.choose(lambda x: x),
) |
As a big proponent of chaining in Pandas and Polars, I would love to see some options to help with code readability with these libraries. Starting each line with a period makes the code easier to understand. |
As a sort of workaround, you can add comments in between the lines:
One might even argue it helps more with readability ;) |
As mentioned by nick4u, this would be a great feature for SQLAlchemy, and I'll add Django to the list: result = (
SomeModel.objects
.filter(...)
.annotate(...)
.prefetch_related(...)
.order_by(...)
) We format like this naturally at my current job, and the main blocking-point of adopting a formatter is that it mangles this syntax regardless of line length (i.e.: the formatter will reformat even code that is within line-length limits). To be fair, the larger pain-point is that formatters in general don't care about what the developer's intent was regarding readability, it just assumes it knows better (or that the dev didn't care to begin with). So both a carefully-crafted, readable piece of code and a long unreadable string will be overridden regardless. The magic-comma is a big step in the right direction, as it lets developers tell the formatter what is more readable. Thankfully, that covers a lot of cases, but not all. As tmke8 commented on #9577, maybe the solution to circumvent the complexity of implementing this type of formatting, at least for now, would be for the formatter to understand "magic-parenthesis". In other words, if it encounters this formatting, apply formatting within the parenthesis, but don't remove them. The example above would be left unchanged, but result = (
SomeModel.objects
.filter(some_very_long_column_name_1__startswith='some_very_long_value', some_very_long_column_name_2__startswith='some_very_long_value')
.order_by(...)
) would become result = (
SomeModel.objects
.filter(
some_very_long_column_name_1__startswith='some_very_long_value',
some_very_long_column_name_2__startswith='some_very_long_value',
)
.order_by(...)
) Also, this would have a great side-effect for multi-line conditions, I think: Currently, this code: if (
self.task
and not self.task.is_canceled
and not self.task.is_finished
): ... gets auto-formatted to if self.task and not self.task.is_canceled and not self.task.is_finished: ... But with "magic-parenthesis", the first formatting would be left as-is. PS: I realize, this comment may be taking the issue in a different direction. If so, let me know and I'll open a new one. |
+1 for this. using such code-style constantly for queries for both alchemy and django |
Great suggestion for a great linter! Has there been any progress so far on this feature? |
+1 CC: @MichaReiser @charliermarsh - Any work or plans for this anytime soon? |
+1 too, also at SQLAlchemy, this would really improve readability if you have this option. |
Just wanted to raise another voice in support of this feature. It seems like Black supports this style of formatting? https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#call-chains I would really prefer to stick with a Rust-based tool but this might be worth switching over. |
Ruff should support call-chain formatting the same as Black. If there are cases where Black applies call-chain formatting and Ruff doesn't, then that's a bug. |
Sorry, you're right — it seems that Ruff matches Black here, however both "fail" in this manner when there is only one method in the "chain", like here. It would be great if cases like that could also be formatted sanely. |
No worries. I do agree that better call chain formatting would be great. |
This is something I miss tremendously from the rust ecosystem. One example:
When formatted becomes:
I think the first example is much more readable, and would love a Python formatter which supported it ❤️
Meta:
I was uncertain about where to make a feature request for the ruff formatter, hope this is the right place!
The text was updated successfully, but these errors were encountered: