spyder-ide / spyder

Official repository for Spyder - The Scientific Python Development Environment
https://www.spyder-ide.org
MIT License
8.19k stars 1.59k forks source link

Not possible to format a file with Black and Autopep8 #21384

Open PhilipYip1988 opened 11 months ago

PhilipYip1988 commented 11 months ago

Format with black should format with autopep8 and then format with black

What steps reproduce the problem?

Sloppy example code:

var1='Hello'
var2="World"
import numpy as np
x=np.array([0,1,2,3,4])
y=np.array([0,2,4,6,8])
import pandas as pd
df=pd.DataFrame({'x':x,"y":y})
import datetime
now=datetime.datetime(year=2023,month=12,day=1)
hour=datetime.timedelta(hours=1)
import collections
counts=collections.Counter([1,2,2,2,3,3])
import itertools
cycle=itertools.cycle([1,2,3])

What is the expected output? What do you see instead?

From what I understand black is an opinionated formatter that formats code using autopep8 and then applies its opinions. In Spyder, the intermediate step format with autopep8 is not carried out when format with black is used.

Example code -> format with black:

var1 = "Hello"
var2 = "World"
import numpy as np

x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 2, 4, 6, 8])
import pandas as pd

df = pd.DataFrame({"x": x, "y": y})
import datetime

now = datetime.datetime(year=2023, month=12, day=1)
hour = datetime.timedelta(hours=1)
import collections

counts = collections.Counter([1, 2, 2, 2, 3, 3])
import itertools

cycle = itertools.cycle([1, 2, 3])

This doesn't look right...

Example code -> format with autopep8

import itertools
import collections
import datetime
import pandas as pd
import numpy as np
var1 = 'Hello'
var2 = "World"
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 2, 4, 6, 8])
df = pd.DataFrame({'x': x, "y": y})
now = datetime.datetime(year=2023, month=12, day=1)
hour = datetime.timedelta(hours=1)
counts = collections.Counter([1, 2, 2, 2, 3, 3])
cycle = itertools.cycle([1, 2, 3])

This looks right.

Example code -> format with autopep8 -> format with black:

import itertools
import collections
import datetime
import pandas as pd
import numpy as np

var1 = "Hello"
var2 = "World"
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 2, 4, 6, 8])
df = pd.DataFrame({"x": x, "y": y})
now = datetime.datetime(year=2023, month=12, day=1)
hour = datetime.timedelta(hours=1)
counts = collections.Counter([1, 2, 2, 2, 3, 3])
cycle = itertools.cycle([1, 2, 3])

This looks right.

Example code -> format with autopep8 -> format with black -> format with blue

import itertools
import collections
import datetime
import pandas as pd
import numpy as np

var1 = 'Hello'
var2 = 'World'
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 2, 4, 6, 8])
df = pd.DataFrame({'x': x, 'y': y})
now = datetime.datetime(year=2023, month=12, day=1)
hour = datetime.timedelta(hours=1)
counts = collections.Counter([1, 2, 2, 2, 3, 3])
cycle = itertools.cycle([1, 2, 3])

Format with blue not currently supported should theoretically look like this.

Versions

Dependencies

# Mandatory:
atomicwrites >=1.2.0                                                        :  1.4.1 (OK)
chardet >=2.0.0                                                             :  5.2.0 (OK)
cloudpickle >=0.5.0                                                         :  2.2.1 (OK)
cookiecutter >=1.6.0                                                        :  2.3.0 (OK)
diff_match_patch >=20181111                                                 :  20230430 (OK)
intervaltree >=3.0.2                                                        :  3.1.0 (OK)
IPython >=7.31.1,<9.0.0,!=8.8.0,!=8.9.0,!=8.10.0,!=8.11.0,!=8.12.0,!=8.12.1 :  8.15.0 (OK)
jedi >=0.17.2,<0.19.0                                                       :  0.18.2 (OK)
jellyfish >=0.7                                                             :  1.0.0 (OK)
jsonschema >=3.2.0                                                          :  4.19.0 (OK)
keyring >=17.0.0                                                            :  24.2.0 (OK)
nbconvert >=4.0                                                             :  7.8.0 (OK)
numpydoc >=0.6.0                                                            :  1.5.0 (OK)
paramiko >=2.4.0                                                            :  3.3.1 (OK)
parso >=0.7.0,<0.9.0                                                        :  0.8.3 (OK)
pexpect >=4.4.0                                                             :  4.8.0 (OK)
pickleshare >=0.4                                                           :  0.7.5 (OK)
psutil >=5.3                                                                :  5.9.5 (OK)
pygments >=2.0                                                              :  2.16.1 (OK)
pylint >=2.5.0,<3.0                                                         :  2.17.5 (OK)
pylint_venv >=3.0.2                                                         :  3.0.2 (OK)
pyls_spyder >=0.4.0                                                         :  0.4.0 (OK)
pylsp >=1.7.4,<1.8.0                                                        :  1.7.4 (OK)
pylsp_black >=1.2.0,<3.0.0                                                  :  1.3.0 (OK)
pyuca >=1.2                                                                 :  1.2 (OK)
qdarkstyle >=3.0.2,<3.2.0                                                   :  3.1 (OK)
qstylizer >=0.2.2                                                           :  0.2.2 (OK)
qtawesome >=1.2.1                                                           :  1.2.3 (OK)
qtconsole >=5.4.2,<5.5.0                                                    :  5.4.4 (OK)
qtpy >=2.1.0                                                                :  2.4.0 (OK)
rtree >=0.9.7                                                               :  1.0.1 (OK)
setuptools >=49.6.0                                                         :  68.2.2 (OK)
sphinx >=0.6.6                                                              :  7.2.6 (OK)
spyder_kernels >=3.0.0b2,<3.0.0b3                                           :  3.0.0b2 (OK)
textdistance >=4.2.0                                                        :  4.5.0 (OK)
three_merge >=0.1.1                                                         :  0.1.1 (OK)
watchdog >=0.10.3                                                           :  3.0.0 (OK)
zmq >=22.1.0                                                                :  25.1.1 (OK)

# Optional:
cython >=0.21                                                               :  3.0.2 (OK)
matplotlib >=3.0.0                                                          :  3.7.2 (OK)
numpy >=1.7                                                                 :  1.25.2 (OK)
pandas >=1.1.1                                                              :  2.1.0 (OK)
scipy >=0.17.0                                                              :  1.11.2 (OK)
sympy >=0.7.3                                                               :  1.12 (OK)
ccordoba12 commented 11 months ago

Hey @PhilipYip1988, thanks for reporting. You said:

From what I understand black is an opinionated formatter that formats code using autopep8 and then applies its opinions.

That is not correct. Each one is a different formatter and doesn't depend on the other to do its job.

However, we could offer menu entries to format a file with different formatters, so users can get the result you posted above in case they are not happy with a single formatter.

PhilipYip1988 commented 11 months ago

Thanks, it seems like I misunderstood how Black worked. Looking at this in more detail, it seems Black is missing some features found in AutoPEP8.

Despite Black stating it is PEP 8 compliant:

The Black Code Style

Black is a PEP 8 compliant opinionated formatter with its own style.

It seems it ignores the following PEP 8 guidelines on imports and doesn't do anything to library imports:

PEP8

Imports should be grouped in the following order:

Standard library imports. Related third party imports. Local application/library specific imports. You should put a blank line between each group of imports.

This seems to have been a requested feature with 93 comments which finally ended up being rejected:

Optimize Imports #333 Not Planned.

And therefore Spyder is implementing Black properly and the above issue is an inherent limitation in Black itself. I also get the same results running Black using the command line.

Having the ability to run AutoPEP8 and then Black in succession from the menu as you suggested will be the best implementation giving features from both.