STYLE Reduce merge conflicts with `force_single_line`
State: closed

- [ ] closes #50274 (Replace xxxx with the GitHub issue number)
- [ ] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [ ] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [ ] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.

Exact commands I ran to do this:
```
 2129  git checkout -b force-single-line
 2130  git fetch upstream
 2131  git reset --hard upstream/main
 2132  sed -i 's/force_grid_wrap = 2/force_single_line = true/g' pyproject.toml 
 2133  pre-commit run isort -a
 2134  git commit -a -m 'force single line = true' --no-verify
```
I then added a handful of missing `noqa: F401` (which you can check in the second commit)

---

To check that there's nothing unrelated, you could do:
```
git reset --hard upstream/main
sed -i 's/force_grid_wrap = 2/force_single_line = true/g' pyproject.toml 
pre-commit run isort -a
git remote add marcogorelli git@github.com:MarcoGorelli/pandas.git
git fetch marcogorelli
git diff marcogorelli/force-single-line
```
and check that the only diff is a handful of `noqa: F401` comments and `import pandas._testing as tm` changes


---


Performance is unaffected, here some results:

<details>
https://www.kaggle.com/code/marcogorelli/asv-pandas-example/notebook?scriptVersionId=113924671

```
[ 50.00%] · For pandas commit 39ceeb7f <force-single-line> (round 2/2):
[ 50.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[ 75.00%] ··· package.TimeImport.time_import                            697±10ms
[ 75.00%] · For pandas commit 48461699 <main> (round 2/2):
[ 75.00%] ·· Building for conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter...
[ 75.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[100.00%] ··· package.TimeImport.time_import                             679±8ms

BENCHMARKS NOT SIGNIFICANTLY CHANGED.
```

```
[ 50.00%] · For pandas commit 39ceeb7f <force-single-line> (round 2/2):
[ 50.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[ 75.00%] ··· package.TimeImport.time_import                             684±6ms
[ 75.00%] · For pandas commit 48461699 <main> (round 2/2):
[ 75.00%] ·· Building for conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter...
[ 75.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[100.00%] ··· package.TimeImport.time_import                            686±10ms

BENCHMARKS NOT SIGNIFICANTLY CHANGED.
```

```
[ 50.00%] · For pandas commit 39ceeb7f <force-single-line> (round 2/2):
[ 50.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[ 75.00%] ··· package.TimeImport.time_import                             695±9ms
[ 75.00%] · For pandas commit 48461699 <main> (round 2/2):
[ 75.00%] ·· Building for conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter...
[ 75.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[100.00%] ··· package.TimeImport.time_import                            734±20ms

BENCHMARKS NOT SIGNIFICANTLY CHANGED.
```

[Another result](https://www.kaggle.com/code/marcogorelli/asv-pandas-example?scriptVersionId=113921936):
```
[ 50.00%] · For pandas commit 39ceeb7f <force-single-line> (round 2/2):
[ 50.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[ 75.00%] ··· package.TimeImport.time_import                             693±8ms
[ 75.00%] · For pandas commit 48461699 <main> (round 2/2):
[ 75.00%] ·· Building for conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter...
[ 75.00%] ·· Benchmarking conda-py3.8-Cython0.29.32-jinja2-matplotlib-numba-numexpr-numpy-odfpy-openpyxl-pyarrow-pytables-scipy-sqlalchemy-xlrd-xlsxwriter
[100.00%] ··· package.TimeImport.time_import                            662±10ms

BENCHMARKS NOT SIGNIFICANTLY CHANGED.
```

In short - it doesn't make a difference to performance

</details>

Labels:
name: Code Style
description: Code style, linting, code_checks

Comments:
We aren't back porting this right?
(Is the plan to wait till no more 1.5.x releases, then merge before 2.0?)
> We aren't back porting this right? (Is the plan to wait till no more 1.5.x releases, then merge before 2.0?)

I think we could just apply the same change to 1.5.x, so:
```
git checkout -b backport-force-single-line
git fetch upstream
git reset --hard upstream/1.5.x
sed -i 's/force_grid_wrap = 2/force_single_line = true/g' pyproject.toml 
pre-commit run isort -a
git commit -a -m 'force single line = true' --no-verify
```

Or waiting until there's no more 1.5.x releases would be fine too
Agree, don't want to do this on 1.5.x. Lets wait till we are through there
sure, marking as draft til then
Would it make sense to replace isort with [reorder_python_imports](https://github.com/asottile/reorder_python_imports/)? I believe we would get the same style but benefit from reorder_python_imports's import re-writing.
`reorder-python-imports` doesn't support Cython files, so I don't think we could/should use it (yet)
Does isort allow us to undo this if we ultimately want to revert? +/-0 on this but feels a bit strange since a user wouldn't naturally write or read code this way
This pull request is stale because it has been open for thirty days with no activity. Please [update](https://pandas.pydata.org/pandas-docs/stable/development/contributing.html#updating-your-pull-request) and respond to this comment if you're still interested in working on this.
> Does isort allow us to undo this if we ultimately want to revert? +/-0 on this but feels a bit strange since a user wouldn't naturally write or read code this way

We could just remove the option, and then it would go back to how it was before

Do users often write or read imports anyway though? I think most contributors just put the import somewhere at the top and then just let isort take care of where and how to place it
@mroeschke @lithomas1 thoughts on getting this in before the RC?

Exact commands I ran to do this:
1. `git fetch upstream && git reset --hard upstream/main && sed -i 's/force_grid_wrap = 2/force_single_line = true/g' pyproject.toml && pre-commit run isort --all-files; git commit -a -m 'force single line = true' --no-verify` (this is the first commit)
2. `pre-commit run ruff --all-files` (I then manually fixed up a handful of missing `noqa`s - this is the second commit)
3. `git ls-files | xargs sed -i 's/from pandas import _testing as tm/import pandas._testing as tm/g'` (this is the third commit)

The third commit was to fix this unwanted pattern

https://github.com/pandas-dev/pandas/blob/fe85cbfb20f3f360ebba62905b93a6f98bf655c1/.pre-commit-config.yaml#L269-L271

which, given the current import style, wasn't actually being caught most of the time
IMO I don't think this should go into the RC yet. Since this is a style change that touches a lot of files, I think there should be a few more positive responses before committing to this.
The goal here is to remove merge conflicts (in the longer term).

Of course while there are backport branches active with these changes this would increase the probability of a merge conflict.

So probably best to do it now (and also apply the change script to 2.0.x now separately) since perhaps it should have been done before the rc.

If we need to do another 1.5.x release then we would maybe have a few merge conflicts to resolve.

I am generally +1 on this change.
> I am generally +1 on this change.

Thanks!

Gonna do a @pandas-dev/pandas-core ping then to hear people's opinions

Motivation for why to do this is to further reduce merge conflicts, see https://github.com/pandas-dev/pandas/issues/50274 for a concrete example of how it would help
> Gonna do a @pandas-dev/pandas-core ping then to hear people's opinions

I find this style really un-natural from a coding standpoint.  Using VSCode, imports are sometimes automatically inserted at the top.  I understand the motivation.  So I'm -1 on it, because it makes the imports look "noisy", but won't stand in the way.

Wondering if a solution is to resolve merge conflicts in backports by round-tripping through this idea.  In other words, we keep the style as it currently is, and then when merging, convert the target to this style and the part being merged to this style, do the merge, and then convert the merged part back to the existing style.  Not sure if this idea is even feasible.

> Using VSCode, imports are sometimes automatically inserted at the top. 

Not sure what you mean, sorry - what's the issue with that? You'll need to run isort/pre-commit anyway
I would also say it looks unnatural and I'm not aware of any human writing style that adopts this.

Do you have a sense as to how often this would reduce/avoid merge conflicts?

It feels like it would roughly on par, in terms of avoiding merge conflicts, as something like

```python
from lib import (
    a,
    b,
    c,
)
```

which is already in use in lots of places.
I give an example here: https://github.com/pandas-dev/pandas/issues/50274#issue-1498486128 . I haven't counted how often this happens, but I opened the issue after having to manually fix imports in several backports when the conflict was just due to going from a single import to multiple

> which is already in use in lots of places.

It's in place everywhere - the issue is in going from
```
from lib import a
```
to
```
from lib import (
    a,
    b,
)
```
Perhaps a less unnatural-looking alternative would be to use `force_grid_wrap = 1`, which would force
```
from lib import (
    a,
)
```
even for single imports. I'll open a separate PR to demonstrate that

EDIT: here it is: https://github.com/pandas-dev/pandas/pull/51693
> > Using VSCode, imports are sometimes automatically inserted at the top.
> 
> Not sure what you mean, sorry - what's the issue with that? You'll need to run isort/pre-commit anyway

I'm not sure of a specific example, but there are times where I'm writing code where I use something that has no `import` statement, and VSCode automatically creates the `import` statement in the right place at the top of the file.  Having said that, you're correct that isort/pre-commit would fix that up automatically.
ew, gross.
The pain point for merge conflicts is in the whatsnew.  id love to see a tool for that. (Also for filling in an issue reference when i dont know the number until i open a pr)
the whatsnew conflicts are orthogonal- but I agree, it would be good to address those too

> ew, gross.

😆 not sure why people don't like this style, but OK, I don't want to force it. Would you be OK with https://github.com/pandas-dev/pandas/pull/51693 instead?
closing in favour of https://github.com/pandas-dev/pandas/pull/51693, which looks like it might have a non-zero chance of passing

> (Also for filling in an issue reference when i dont know the number until i open a pr)

here you go https://ichard26.github.io/next-pr-number/