RFC isort as linter and import sorter

What do we think of [`isort`](https://github.com/PyCQA/isort)? I've seen it in other projects and seems like a sane tool.

We could add it to our linter and pre-commit hooks if others think it's a good thing. It does look nice to me.

Looking at the import section of `test_common.py`, we have:

``` python
import os
import warnings
import sys
import re
import pkgutil
from inspect import isgenerator, signature, Parameter
from itertools import product, chain
from functools import partial

import pytest
import numpy as np

from sklearn.utils import all_estimators
from sklearn.utils._testing import ignore_warnings
from sklearn.exceptions import ConvergenceWarning
from sklearn.exceptions import FitFailedWarning
from sklearn.utils.estimator_checks import check_estimator

import sklearn

from sklearn.decomposition import PCA
from sklearn.linear_model._base import LinearClassifierMixin
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import Ridge
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RandomizedSearchCV
from sklearn.experimental import enable_halving_search_cv  # noqa
from sklearn.model_selection import HalvingGridSearchCV
from sklearn.model_selection import HalvingRandomSearchCV
from sklearn.pipeline import make_pipeline

from sklearn.utils import IS_PYPY
from sklearn.utils._tags import _DEFAULT_TAGS, _safe_tags
from sklearn.utils._testing import (
    SkipTest,
    set_random_state,
)
from sklearn.utils.estimator_checks import (
    _construct_instance,
    _set_checking_parameters,
    _get_check_estimator_ids,
    check_class_weight_balanced_linear_classifier,
    parametrize_with_checks,
    check_dataframe_column_names_consistency,
    check_n_features_in_after_fitting,
    check_transformer_get_feature_names_out,
    check_transformer_get_feature_names_out_pandas,
)
```
And running `isort --profile black sklearn/tests/test_common.py` will result in:

``` py
import os
import pkgutil
import re
import sys
import warnings
from functools import partial
from inspect import Parameter, isgenerator, signature
from itertools import chain, product

import numpy as np
import pytest

import sklearn
from sklearn.decomposition import PCA
from sklearn.exceptions import ConvergenceWarning, FitFailedWarning
from sklearn.experimental import enable_halving_search_cv  # noqa
from sklearn.linear_model import LogisticRegression, Ridge
from sklearn.linear_model._base import LinearClassifierMixin
from sklearn.model_selection import (
    GridSearchCV,
    HalvingGridSearchCV,
    HalvingRandomSearchCV,
    RandomizedSearchCV,
)
from sklearn.pipeline import make_pipeline
from sklearn.utils import IS_PYPY, all_estimators
from sklearn.utils._tags import _DEFAULT_TAGS, _safe_tags
from sklearn.utils._testing import SkipTest, ignore_warnings, set_random_state
from sklearn.utils.estimator_checks import (
    _construct_instance,
    _get_check_estimator_ids,
    _set_checking_parameters,
    check_class_weight_balanced_linear_classifier,
    check_dataframe_column_names_consistency,
    check_estimator,
    check_n_features_in_after_fitting,
    check_transformer_get_feature_names_out,
    check_transformer_get_feature_names_out_pandas,
    parametrize_with_checks,
)
```

with the following diff:

```diff
diff --git a/sklearn/tests/test_common.py b/sklearn/tests/test_common.py
index 251f0831f..d43524292 100644
--- a/sklearn/tests/test_common.py
+++ b/sklearn/tests/test_common.py
@@ -7,52 +7,44 @@ General tests for all estimators in sklearn.
 # License: BSD 3 clause
 
 import os
-import warnings
-import sys
-import re
 import pkgutil
-from inspect import isgenerator, signature, Parameter
-from itertools import product, chain
+import re
+import sys
+import warnings
 from functools import partial
+from inspect import Parameter, isgenerator, signature
+from itertools import chain, product
 
-import pytest
 import numpy as np
-
-from sklearn.utils import all_estimators
-from sklearn.utils._testing import ignore_warnings
-from sklearn.exceptions import ConvergenceWarning
-from sklearn.exceptions import FitFailedWarning
-from sklearn.utils.estimator_checks import check_estimator
+import pytest
 
 import sklearn
-
 from sklearn.decomposition import PCA
-from sklearn.linear_model._base import LinearClassifierMixin
-from sklearn.linear_model import LogisticRegression
-from sklearn.linear_model import Ridge
-from sklearn.model_selection import GridSearchCV
-from sklearn.model_selection import RandomizedSearchCV
+from sklearn.exceptions import ConvergenceWarning, FitFailedWarning
 from sklearn.experimental import enable_halving_search_cv  # noqa
-from sklearn.model_selection import HalvingGridSearchCV
-from sklearn.model_selection import HalvingRandomSearchCV
+from sklearn.linear_model import LogisticRegression, Ridge
+from sklearn.linear_model._base import LinearClassifierMixin
+from sklearn.model_selection import (
+    GridSearchCV,
+    HalvingGridSearchCV,
+    HalvingRandomSearchCV,
+    RandomizedSearchCV,
+)
 from sklearn.pipeline import make_pipeline
-
-from sklearn.utils import IS_PYPY
+from sklearn.utils import IS_PYPY, all_estimators
 from sklearn.utils._tags import _DEFAULT_TAGS, _safe_tags
-from sklearn.utils._testing import (
-    SkipTest,
-    set_random_state,
-)
+from sklearn.utils._testing import SkipTest, ignore_warnings, set_random_state
 from sklearn.utils.estimator_checks import (
     _construct_instance,
-    _set_checking_parameters,
     _get_check_estimator_ids,
+    _set_checking_parameters,
     check_class_weight_balanced_linear_classifier,
-    parametrize_with_checks,
     check_dataframe_column_names_consistency,
+    check_estimator,
     check_n_features_in_after_fitting,
     check_transformer_get_feature_names_out,
     check_transformer_get_feature_names_out_pandas,
+    parametrize_with_checks,
 )
```

COMMENT:
FWIW I have been using pre-commit.ci in another project and did a sprint with new contributors using it. It does indeed take some getting used to it pushing fixes to PRs but overall I find it's really useful for contributors who generally don't setup pre-commit or other dev tools right.

I would argue that aside from sprints for new contributors, contributors with a least some experience (or former devs) don't read contributing guide. Say you want to fix something in pandas. Are you going to read their contributing guide to see whatever style guide they have? No, you are going to make the fix open a PR and see if the CI is happy. Even if you read it last year, by now the style/tools used might have changed.

So in that sense pre-commit.ci does make the workflow smoother. As for very new contributors, that does mean they need to know how to fix merge conflicts, but at least that's a more useful skill than figuring out how to install the right dev tools.

> the downside is that this cli tool is package specific, 

Yes, for code styling pre-commit is the way to go IMO. Then it doesn't even matter what it runs (black, isort or others) there is just 1 dev dependency. 

But that's in the long term, in the short term, I'm indeed not sure what would be the small iterative improvements over the current situation.

Labels: Build / CI, RFC