grantjenks / blue Goto Github PK
View Code? Open in Web Editor NEWThe slightly less uncompromising Python code formatter.
Home Page: https://blue.readthedocs.io/
License: Other
The slightly less uncompromising Python code formatter.
Home Page: https://blue.readthedocs.io/
License: Other
Current logic for module docstrings relies on the string being at the top of the file. Need to handle encodings and comments and blank lines.
When building documentation for 0.5.1 (from the tarball from GitHub) for the package for openSUSE I got this failure:
[ 4s] + cd docs
[ 4s] + PYTHONPATH=../build/lib
[ 4s] + make html
[ 4s] Running Sphinx v3.3.1
[ 4s]
[ 4s] Configuration error:
[ 4s] There is a programmable error in your configuration file:
[ 4s]
[ 4s] Traceback (most recent call last):
[ 4s] File "/usr/lib/python3.8/site-packages/sphinx/config.py", line 319, in eval_config_file
[ 4s] execfile_(filename, namespace)
[ 4s] File "/usr/lib/python3.8/site-packages/sphinx/util/pycompat.py", line 89, in execfile_
[ 4s] exec(code, _globals)
[ 4s] File "/home/abuild/rpmbuild/BUILD/blue-0.5.1/docs/conf.py", line 22, in <module>
[ 4s] project = blue.__title__.title()
[ 4s] AttributeError: module 'blue' has no attribute '__title__'
[ 4s]
[ 4s] make: *** [Makefile:20: html] Error 2
Seems like I'm unable to get blue to run anymore...
I consistently get the following error:
Traceback (most recent call last): File "/Users/gturbyne/workspace/sonarqube-tools/build/sonarqube-tools/environments/satellites/codeQuality/bin/blue", line 5, in <module> from blue import main File "/Users/gturbyne/workspace/sonarqube-tools/build/sonarqube-tools/environments/satellites/codeQuality/lib/python3.7/site-packages/blue/__init__.py", line 10, in <module> import black File "/Users/gturbyne/workspace/sonarqube-tools/build/sonarqube-tools/environments/satellites/codeQuality/lib/python3.7/site-packages/black/__init__.py", line 371, in <module> ) -> None: File "/Users/gturbyne/workspace/sonarqube-tools/build/sonarqube-tools/environments/satellites/python/lib/python3.7/site-packages/click/decorators.py", line 170, in decorator _param_memo(f, OptionClass(param_decls, **attrs)) File "/Users/gturbyne/workspace/sonarqube-tools/build/sonarqube-tools/environments/satellites/python/lib/python3.7/site-packages/click/core.py", line 1460, in __init__ Parameter.__init__(self, param_decls, type=type, **attrs) TypeError: __init__() got an unexpected keyword argument 'hidden' DURATION: 0.51s
I have a black formatted json blob that looks like the following:
return jsonify(data={
'id': 123,
'name': 'A Content Type',
'type': 'json',
'field': [
{
'name': 'headline',
'type': 'string'
},
{
'name': 'url',
'type': 'string'
}
]
})
After formatting with blue the formatting was changed to the following:
return jsonify(
data={
'id': 123,
'name': 'A Content Type',
'type': 'json',
'field': [{'name': 'headline', 'type': 'string'}, {'name': 'url', 'type': 'string'}],
}
)
My own personal preference is towards the original formatting since it's much easier to identify field count and pick out the name fields at a glance.
When I visit https://blue.readthedocs.io/en/latest/ , I donβt see the latest docs. Is it just me (maybe caching issue?) or is something broken in the RTD integration?
Replace the word "black" in the --target-version option?
Support setup.cfg for configuration in addition to pyproject.toml
Decide whether to monkey-patch CACHE_DIR.
Black has https://black.now.sh/ but I want blue!
Black supports "blackd" which is used by some for IDE integration. Let's add support for "blued" too!
Flake8 v5 was just released earlier today. Unfortunately this breaks blue
as it now crashes with this error:
Traceback (most recent call last):
File "/tmp/tox/prisma-client-py/lint/lib/python3.9/site-packages/blue/__init__.py", line 397, in <module>
BaseConfigParser = flake8_config.ConfigParser # flake8 v4
AttributeError: module 'flake8.options.config' has no attribute 'ConfigParser'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/tox/prisma-client-py/lint/bin/blue", line 5, in <module>
from blue import main
File "/tmp/tox/prisma-client-py/lint/lib/python3.9/site-packages/blue/__init__.py", line 399, in <module>
BaseConfigParser = flake8_config.MergedConfigParser # flake8 v3
AttributeError: module 'flake8.options.config' has no attribute 'MergedConfigParser'
Constraining the flake8 dependency to v4 fixes the error.
Need to monkey-patch def parse_pyproject_toml(path_config: str) -> Dict[str, Any]:
to support a "blue" section.
I'm not thrilled with this diff:
def __eq__(self, that):
if not isinstance(that, type(self)):
return NotImplemented
- return (self.__slots__ == that.__slots__
- and all(item == iota for item, iota in zip(self, that)))
+ return self.__slots__ == that.__slots__ and all(
+ item == iota for item, iota in zip(self, that)
+ )
def __repr__(self):
Right now, it reports the black
version number, but it should probably do both. I.e. instead of
% blue --version
blue, version 20.8b1
It should say
% blue --version
blue, version 0.5.2; based on black 20.8b1
or some such.
Black does this, yuck!
- whitespace = orig_line[:-len(line)]
+ whitespace = orig_line[: -len(line)]
Add a few test cases for quoting.
The idea is to add a # fmt: skip
comment hanging at the end of a line and that would skip reformatting that statement. It avoids the need to wrap the line in fmt: on
/fmt: off
boundaries.
black
expands brackets into multiple lines, where this:
raise ValidationError({
NON_FIELD_ERRORS: [_("Don't do that!")],
})
raise ValidationError(
{
NON_FIELD_ERRORS: [_("Don't do that!")],
}
)
The coalesced bracket version is much to be preferred in my opinion. It would be great to have a configuration option to coalesce rather than expand brackets.
I noticed blue is failing for a specific Python 3.9 syntax:
def get_dec_dec():
def get_dec():
def dec(func):
print(func)
return dec
return get_dec
@get_dec_dec()()
def foo():
...
error: cannot format example.py: Cannot parse: 8:14: @get_dec_dec()()
Oh no! π₯ π π₯
1 file failed to reformat
It would be nice to support this so I was wondering if it would be possible to port changes from the latest black to blue.
Let's consider not squeezing hanging comments to the left, e.g. not doing this:
- def _coerce(self, value, default: Optional[int] = 0) -> Optional[int]: # type: ignore[no-untyped-def]
+ def _coerce(self, value, default: Optional[int] = 0) -> Optional[int]: # type: ignore[no-untyped-def]
And here's an egregious example from flufl.i18n:
- aqua = 'aardvarks' # noqa: F841
- blue = 'badgers' # noqa: F841
- cyan = 'cats' # noqa: F841
+ aqua = 'aardvarks' # noqa: F841
+ blue = 'badgers' # noqa: F841
+ cyan = 'cats' # noqa: F841
The latter is definitely less readable.
Scientific programming has a lot of formulas, it would help if a formatter leaves multiplication alone.
So,
a + 4*b - c**3
should be left alone.
The internal errors reference "black" in assert_equivalent and assert_stable. Change those to "blue"
% blue -t py39
Usage: blue [OPTIONS] [SRC]...
Try 'blue -h' for help.
Error: Invalid value for '-t' / '--target-version': invalid choice: py39. (choose from py27, py33, py34, py35, py36, py37, py38)
What it should do is:
% blue -t py39
No Path provided. Nothing to do π΄
This is because we're depending on black 20.8b1
which also doesn't support py39
. However black
git HEAD does support it so maybe we just wait for the next (non-beta) release. Alternatively, maybe we can just monkeypatch support aligning py39
to py38
.
Some examples?
CACHE_DIR = Path(user_cache_dir("black", version=__version__))
STDIN_PLACEHOLDER = "__BLACK_STDIN_FILENAME__"
config = pyproject_toml.get("tool", {}).get("black", {})
BREAK_MARK = "@@@@@ BLACK BREAKPOINT MARKER @@@@@"
f"INTERNAL ERROR: Black produced invalid code: {exc}. Please report a bug"
I think the most significant things may be the CACHE_DIR
and the pyproject.toml
config to avoid corrupting/conflicting with Black.
People put in semicolons intentionally. It is almost never an accidental occurrence. We should respect the user's explicit intention.
In debugging code, there are natural logical pairings that are almost always done together. This facilitates easily inserting, moving, copying, and removal of the logical pair (which the user thinks of a single discrete step rather than a series of steps):
import pdb; pdb.pm()
For timing code, the start/action/end/report cycle form a natural, logical grouping that leaves the timed steps in their logical, consecutive sequence:
start = time(); step1(x); end = time(); print(end - start)
start = time(); step2(y); end = time(); print(end - start)
In Lib/cgitb.py, these statements naturally occur as a pair:
import cgitb; cgitb.enable()
In Tools/scripts/var_accessbenchmark.py, the existing code looks pleasing to the eye and makes it easy to see how many times v_local
is being called:
def read_local(trials=trials):
v_local = 1
for t in trials:
v_local; v_local; v_local; v_local; v_local
v_local; v_local; v_local; v_local; v_local
v_local; v_local; v_local; v_local; v_local
v_local; v_local; v_local; v_local; v_local
v_local; v_local; v_local; v_local; v_local
In Lib/idlelib/multicall.py, we see a typical use in grouping constants. These could be split on separate lines but it distracts from the overall flow of reading the module and makes it more difficult to relate back to the source of this information. I could go either way on this one but think it is best to respect the author's intention:
# the event type constants, which define the meaning of mc_type
MC_KEYPRESS=0; MC_KEYRELEASE=1; MC_BUTTONPRESS=2; MC_BUTTONRELEASE=3;
MC_ACTIVATE=4; MC_CIRCULATE=5; MC_COLORMAP=6; MC_CONFIGURE=7;
MC_DEACTIVATE=8; MC_DESTROY=9; MC_ENTER=10; MC_EXPOSE=11; MC_FOCUSIN=12;
MC_FOCUSOUT=13; MC_GRAVITY=14; MC_LEAVE=15; MC_MAP=16; MC_MOTION=17;
MC_MOUSEWHEEL=18; MC_PROPERTY=19; MC_REPARENT=20; MC_UNMAP=21; MC_VISIBILITY=22;
# the modifier state constants, which define the meaning of mc_state
MC_SHIFT = 1<<0; MC_CONTROL = 1<<2; MC_ALT = 1<<3; MC_META = 1<<5
MC_OPTION = 1<<6; MC_COMMAND = 1<<7
In Lib/mailcap.py, we see this pair several times. It is a common pattern for consuming a value and advancing an index. The reason the author put them on the same line is that it makes it easy to see verify that every consumed value also advances the index. It would be a mistake to do the first without the second. So, the formatter should respect the logical grouping of statements:
c = field[i:i+1]; i = i+1
From flufl.lock 's setup.py
. I'm not sure why blue changes some single-quotes to double quotes in some cases. Note that it doesn't transform them all, and the ones it does change don't have embedded single-quotes.
@@ -11,37 +11,37 @@
with open('README.rst') as fp:
readme = fp.read()
setup(
- name='flufl.lock',
+ name="flufl.lock",
version=__version__,
author='Barry Warsaw',
author_email='[email protected]',
description=__doc__,
long_description=readme,
long_description_content_type='text/x-rst',
license='Apache 2.0',
keywords='locking locks lock',
url='https://flufllock.readthedocs.io',
download_url='https://pypi.python.org/pypi/flufl.lock',
- packages=find_namespace_packages(where='.', exclude=['test*', 'docs']),
+ packages=find_namespace_packages(where=".", exclude=['test*', 'docs']),
namespace_packages=['flufl'],
include_package_data=True,
# readthedocs builds fail unless zip_safe is False.
zip_safe=False,
python_requires='>=3.6',
install_requires=[
'atpublic',
'psutil',
'typing_extensions;python_version<"3.8"',
- ],
+ ],
project_urls={
'Documentation': 'https://flufllock.readthedocs.io',
'Source': 'https://gitlab.com/warsaw/flufl.lock.git',
'Tracker': 'https://gitlab.com/warsaw/flufl.lock/issues',
- },
+ },
classifiers=[
'Development Status :: 5 - Production/Stable',
'Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
Per PEP8:
If operators with different priorities are used, consider adding whitespace around the operators with the lowest priority(ies). Use your own judgment; however, never use more than one space, and always have the same amount of whitespace on both sides of a binary operator:
# Correct:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
Note that SymPy does the right thing, so we know there is enough semantic information to do this correctly:
>>> from sympy import var
>>> var('x')
x
>>> ((3*x + 5) * (2*x - 4)).expand()
6*x**2 - 2*x - 20
Support tox.ini for configuration in addition to pyproject.toml
I don't like this, but I get why it's happening. Should it?
--- /tmp/foo.py 2021-01-13 01:37:02.895096 +0000
+++ /tmp/foo.py 2021-01-13 01:37:15.606447 +0000
@@ -1,6 +1,6 @@
-x = """
+x = '''
This is a TQDQS.
It probably should not be converted
into a TQSQS.
-"""
+'''
Use this to gather ideas for formatting improvements here.
I get:
[ 8s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/blue/__init__.py:397: in main
[ 8s] black.main()
[ 8s] /usr/lib/python3.9/site-packages/click/core.py:1128: in __call__
[ 8s] return self.main(*args, **kwargs)
[ 8s] /usr/lib/python3.9/site-packages/click/core.py:1052: in main
[ 8s] with self.make_context(prog_name, args, **extra) as ctx:
[ 8s] /usr/lib/python3.9/site-packages/click/core.py:914: in make_context
[ 8s] self.parse_args(ctx, args)
[ 8s] /usr/lib/python3.9/site-packages/click/core.py:1370: in parse_args
[ 8s] value, args = param.handle_parse_result(ctx, opts, args)
[ 8s] /usr/lib/python3.9/site-packages/click/core.py:2347: in handle_parse_result
[ 8s] value = self.process_value(ctx, value)
[ 8s] /usr/lib/python3.9/site-packages/click/core.py:2309: in process_value
[ 8s] value = self.callback(ctx, self, value)
[ 8s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/blue/__init__.py:357: in read_configs
[ 8s] result = black.read_pyproject_toml(ctx, param, value)
[ 8s] /usr/lib/python3.9/site-packages/black/__init__.py:119: in read_pyproject_toml
[ 8s] config = parse_pyproject_toml(value)
[ 8s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/blue/__init__.py:267: in parse_pyproject_toml
[ 8s] pyproject_toml = tomli.load(f) # type: ignore # due to deprecated API usage
[ 8s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[ 8s]
[ 8s] __fp = <_io.TextIOWrapper name='/home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/config_pyproject/pyproject.toml' mode='r' encoding='utf8'>
[ 8s]
[ 8s] def load(__fp: BinaryIO, *, parse_float: ParseFloat = float) -> dict[str, Any]:
[ 8s] """Parse TOML from a binary file object."""
[ 8s] b = __fp.read()
[ 8s] try:
[ 8s] s = b.decode()
[ 8s] except AttributeError:
[ 8s] > raise TypeError(
[ 8s] "File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`"
[ 8s] ) from None
[ 8s] E TypeError: File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`
[ 8s]
[ 8s] /usr/lib/python3.9/site-packages/tomli/_parser.py:63: TypeError
Something about this just reads/seems strange to me - it's not what I'd expect.
- os.environ['JAVA_HOME'] = '/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/'
+ os.environ[
+ 'JAVA_HOME'
+ ] = '/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/'
Show we remove the --skip-string-normalization switch? Otherwise seems pretty similar to black.
It occurred to me this evening that an alternative design is possible. Rather than monkey-patch black, we could just run black and then post-process the result. The post-processor would simply visit and correct all the string quoting. I'm not sure I like the idea of a "wrapper" but it is less invasive.
Maybe black could be "extensible" through hooks/entry-points in some way. The post-processing could be a supported feature.
Do not add a blank line after single-line docstrings (compliant with PEP257).
@public
class Template(string.Template):
"""Match any attribute path."""
idpattern = r'[_a-z][_a-z0-9.]*'
I have a PR that uses @typing.overload. You'll notice that in the stdlib documentation, there are no blank lines after the ellipsis in the overload definitions. @gvanrossum even says that they don't traditionally do this. However, without the blank lines, black
(and thus blue
) complains. Perhaps blue
can do better.
E.g.
@overload
def process(response: None) -> None:
...
@overload
def process(response: int) -> tuple[int, str]:
...
@overload
def process(response: bytes) -> str:
...
def process(response):
<actual implementation>
Black makes a mess of this code in Lib/statistics.py:
def _normal_dist_inv_cdf(p, mu, sigma):
# There is no closed-form solution to the inverse CDF for the normal
# distribution, so we use a rational approximation instead:
# Wichura, M.J. (1988). "Algorithm AS241: The Percentage Points of the
# Normal Distribution". Applied Statistics. Blackwell Publishing. 37
# (3): 477β484. doi:10.2307/2347330. JSTOR 2347330.
q = p - 0.5
if fabs(q) <= 0.425:
r = 0.180625 - q * q
# Hash sum: 55.88319_28806_14901_4439
num = (((((((2.50908_09287_30122_6727e+3 * r +
3.34305_75583_58812_8105e+4) * r +
6.72657_70927_00870_0853e+4) * r +
4.59219_53931_54987_1457e+4) * r +
1.37316_93765_50946_1125e+4) * r +
1.97159_09503_06551_4427e+3) * r +
1.33141_66789_17843_7745e+2) * r +
3.38713_28727_96366_6080e+0) * q
den = (((((((5.22649_52788_52854_5610e+3 * r +
2.87290_85735_72194_2674e+4) * r +
3.93078_95800_09271_0610e+4) * r +
2.12137_94301_58659_5867e+4) * r +
5.39419_60214_24751_1077e+3) * r +
6.87187_00749_20579_0830e+2) * r +
4.23133_30701_60091_1252e+1) * r +
1.0)
x = num / den
return mu + (x * sigma)
...
For this code in Lib/test/test_random.py, Black does a nice job with the internal list, but it turns the rest of the formula into confetti:
def gamma(z, sqrt2pi=(2.0*pi)**0.5):
# Reflection to right half of complex plane
if z < 0.5:
return pi / sin(pi*z) / gamma(1.0-z)
# Lanczos approximation with g=7
az = z + (7.0 - 0.5)
return az ** (z-0.5) / exp(az) * sqrt2pi * fsum([
0.9999999999995183,
676.5203681218835 / z,
-1259.139216722289 / (z+1.0),
771.3234287757674 / (z+2.0),
-176.6150291498386 / (z+3.0),
12.50734324009056 / (z+4.0),
-0.1385710331296526 / (z+5.0),
0.9934937113930748e-05 / (z+6.0),
0.1659470187408462e-06 / (z+7.0),
])
It's not clear what general formatting rule should be applied, but it is clear that Black makes choices that don't work well for numeric and scientific computing. Almost any non-trivial formula is made worse by running it through Black. Sympy may have some useful guidance here β they've already spent some time wresting with formula formatting.
Function docstrings are getting converted to single quotes. Probably a problem with is_docstring()
Pin the version of black used to 20.8b1
Docstrings should always use triple double quotes. Don't fallback to Black's formatting (if it's avoidable).
Currently blue (version 0.7.0) supports most features of Python 3.10 via black (version 21.7.b0), but not the match statement. Black version 21.12b0 apparently does (see black issue #2662. However, running blue with that version of black produces this error:
$ blue src
Traceback (most recent call last):
File ".../venv/bin/blue", line 8, in <module>
sys.exit(main())
File ".../venv/lib/python3.10/site-packages/blue/__init__.py", line 385, in main
assert config_param.name == 'config'
AssertionError
Apparently, blue does not allow the option --target-version py310
nor the equivalent to be set in the pyproject.toml file (tools.black ...).
Version info for current version of blue:
$ poetry show blue
name : blue
version : 0.7.0
description : Blue -- Some folks like black but I prefer blue.
dependencies
- black 21.7b0
- flake8 3.8.4
Given that blue only patches black and that black does not consider version 21.12b0 to fully support match statements, is it premature to ask that blue can allow the interim version of black to be used with it?
It would be nice to retain the whitespace following lines even in multi-line expressions, such as list or dict definitions. Here is a (truncated) example where we are defining named fields in a binary format:
header_dtd = [
- ('sizeof_hdr', 'i4'), # 0; must be 348
- ('data_type', 'S10'), # 4; unused
- ('db_name', 'S18'), # 14; unused
- ('extents', 'i4'), # 32; unused
- ('session_error', 'i2'), # 36; unused
- ('regular', 'S1'), # 38; unused
- ('dim_info', 'u1'), # 39; MRI slice ordering code
- ('dim', 'i2', (8,)), # 40; data array dimensions
+ ('sizeof_hdr', 'i4'), # 0; must be 348
+ ('data_type', 'S10'), # 4; unused
+ ('db_name', 'S18'), # 14; unused
+ ('extents', 'i4'), # 32; unused
+ ('session_error', 'i2'), # 36; unused
+ ('regular', 'S1'), # 38; unused
+ ('dim_info', 'u1'), # 39; MRI slice ordering code
+ ('dim', 'i2', (8,)), # 40; data array dimensions
]
I realize this is going to be hard to get right 100% of the time, especially if other parts of the expression need to be shifted. I can just #fmt: off
it, but would there be any interest in handling this case?
Using: blue, version 0.9.0, based on black 22.1.0
Got a nice message from Luciano:
"Thank you so much for making blue
, Grant & contributors!"
-- Luciano Ramalho
And he said we could put it in our readme :)
Probably would be good to link to the Python list email ... says more nice things.
When packaging for openSUSE (after applying all patches from #66, so that is not the issue) I get these errors:
[ 28s] + PYTHONPATH=/home/abuild/rpmbuild/BUILDROOT/python-blue-0.8.0-0.x86_64/usr/lib/python3.9/site-packages
[ 28s] + PYTHONDONTWRITEBYTECODE=1
[ 28s] + pytest-3.9 --ignore=_build.python39 --ignore=_build.python310 --ignore=_build.python38 -v
[ 28s] ============================= test session starts ==============================
[ 28s] platform linux -- Python 3.9.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -- /usr/bin/python3.9
[ 28s] cachedir: .pytest_cache
[ 28s] rootdir: /home/abuild/rpmbuild/BUILD/blue-0.8.0, configfile: tox.ini, testpaths: blue, docs, tests
[ 29s] collecting ... collected 8 items
[ 29s]
[ 29s] tests/test_blue.py::test_good_dirs[config_setup] FAILED [ 12%]
[ 29s] tests/test_blue.py::test_good_dirs[config_tox] FAILED [ 25%]
[ 29s] tests/test_blue.py::test_good_dirs[config_blue] FAILED [ 37%]
[ 29s] tests/test_blue.py::test_good_dirs[config_pyproject] FAILED [ 50%]
[ 29s] tests/test_blue.py::test_good_dirs[good_cases] FAILED [ 62%]
[ 29s] tests/test_blue.py::test_bad_dirs[bad_cases] FAILED [ 75%]
[ 29s] tests/test_blue.py::test_main PASSED [ 87%]
[ 29s] tests/test_blue.py::test_version PASSED [100%]
[ 29s]
[ 29s] =================================== FAILURES ===================================
[ 29s] _________________________ test_good_dirs[config_setup] _________________________
[ 29s]
[ 29s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f702f5393a0>
[ 29s] test_dir = PosixPath('/home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/config_setup')
[ 29s]
[ 29s] @pytest.mark.parametrize(
[ 29s] 'test_dir',
[ 29s] [
[ 29s] 'config_setup',
[ 29s] 'config_tox',
[ 29s] 'config_blue',
[ 29s] 'config_pyproject',
[ 29s] 'good_cases',
[ 29s] ],
[ 29s] )
[ 29s] def test_good_dirs(monkeypatch, test_dir):
[ 29s] test_dir = tests_dir / test_dir
[ 29s] monkeypatch.chdir(test_dir)
[ 29s] monkeypatch.setattr('sys.argv', ['blue', '--check', '.'])
[ 29s] for path in test_dir.rglob('*'):
[ 29s] path.touch() # Invalidate file caches in Blue.
[ 29s] black.find_project_root.cache_clear()
[ 29s] with pytest.raises(SystemExit) as exc_info:
[ 29s] asyncio.set_event_loop(asyncio.new_event_loop())
[ 29s] blue.main()
[ 29s] > assert exc_info.value.code == 0
[ 29s] E assert 123 == 0
[ 29s] E +123
[ 29s] E -0
[ 29s]
[ 29s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/test_blue.py:32: AssertionError
[ 29s] ----------------------------- Captured stderr call -----------------------------
[ 29s] error: cannot format example.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s]
[ 29s] Oh no! π₯ π π₯
[ 29s] 1 file would fail to reformat.
[ 29s] __________________________ test_good_dirs[config_tox] __________________________
[ 29s]
[ 29s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f702f5b0070>
[ 29s] test_dir = PosixPath('/home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/config_tox')
[ 29s]
[ 29s] @pytest.mark.parametrize(
[ 29s] 'test_dir',
[ 29s] [
[ 29s] 'config_setup',
[ 29s] 'config_tox',
[ 29s] 'config_blue',
[ 29s] 'config_pyproject',
[ 29s] 'good_cases',
[ 29s] ],
[ 29s] )
[ 29s] def test_good_dirs(monkeypatch, test_dir):
[ 29s] test_dir = tests_dir / test_dir
[ 29s] monkeypatch.chdir(test_dir)
[ 29s] monkeypatch.setattr('sys.argv', ['blue', '--check', '.'])
[ 29s] for path in test_dir.rglob('*'):
[ 29s] path.touch() # Invalidate file caches in Blue.
[ 29s] black.find_project_root.cache_clear()
[ 29s] with pytest.raises(SystemExit) as exc_info:
[ 29s] asyncio.set_event_loop(asyncio.new_event_loop())
[ 29s] blue.main()
[ 29s] > assert exc_info.value.code == 0
[ 29s] E assert 123 == 0
[ 29s] E +123
[ 29s] E -0
[ 29s]
[ 29s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/test_blue.py:32: AssertionError
[ 29s] ----------------------------- Captured stderr call -----------------------------
[ 29s] error: cannot format example.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s]
[ 29s] Oh no! π₯ π π₯
[ 29s] 1 file would fail to reformat.
[ 29s] _________________________ test_good_dirs[config_blue] __________________________
[ 29s]
[ 29s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f702f5aa550>
[ 29s] test_dir = PosixPath('/home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/config_blue')
[ 29s]
[ 29s] @pytest.mark.parametrize(
[ 29s] 'test_dir',
[ 29s] [
[ 29s] 'config_setup',
[ 29s] 'config_tox',
[ 29s] 'config_blue',
[ 29s] 'config_pyproject',
[ 29s] 'good_cases',
[ 29s] ],
[ 29s] )
[ 29s] def test_good_dirs(monkeypatch, test_dir):
[ 29s] test_dir = tests_dir / test_dir
[ 29s] monkeypatch.chdir(test_dir)
[ 29s] monkeypatch.setattr('sys.argv', ['blue', '--check', '.'])
[ 29s] for path in test_dir.rglob('*'):
[ 29s] path.touch() # Invalidate file caches in Blue.
[ 29s] black.find_project_root.cache_clear()
[ 29s] with pytest.raises(SystemExit) as exc_info:
[ 29s] asyncio.set_event_loop(asyncio.new_event_loop())
[ 29s] blue.main()
[ 29s] > assert exc_info.value.code == 0
[ 29s] E assert 123 == 0
[ 29s] E +123
[ 29s] E -0
[ 29s]
[ 29s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/test_blue.py:32: AssertionError
[ 29s] ----------------------------- Captured stderr call -----------------------------
[ 29s] error: cannot format example.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s]
[ 29s] Oh no! π₯ π π₯
[ 29s] 1 file would fail to reformat.
[ 29s] _______________________ test_good_dirs[config_pyproject] _______________________
[ 29s]
[ 29s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f702f5b4b20>
[ 29s] test_dir = PosixPath('/home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/config_pyproject')
[ 29s]
[ 29s] @pytest.mark.parametrize(
[ 29s] 'test_dir',
[ 29s] [
[ 29s] 'config_setup',
[ 29s] 'config_tox',
[ 29s] 'config_blue',
[ 29s] 'config_pyproject',
[ 29s] 'good_cases',
[ 29s] ],
[ 29s] )
[ 29s] def test_good_dirs(monkeypatch, test_dir):
[ 29s] test_dir = tests_dir / test_dir
[ 29s] monkeypatch.chdir(test_dir)
[ 29s] monkeypatch.setattr('sys.argv', ['blue', '--check', '.'])
[ 29s] for path in test_dir.rglob('*'):
[ 29s] path.touch() # Invalidate file caches in Blue.
[ 29s] black.find_project_root.cache_clear()
[ 29s] with pytest.raises(SystemExit) as exc_info:
[ 29s] asyncio.set_event_loop(asyncio.new_event_loop())
[ 29s] blue.main()
[ 29s] > assert exc_info.value.code == 0
[ 29s] E assert 123 == 0
[ 29s] E +123
[ 29s] E -0
[ 29s]
[ 29s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/test_blue.py:32: AssertionError
[ 29s] ----------------------------- Captured stderr call -----------------------------
[ 29s] error: cannot format example.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s]
[ 29s] Oh no! π₯ π π₯
[ 29s] 1 file would fail to reformat.
[ 29s] __________________________ test_good_dirs[good_cases] __________________________
[ 29s]
[ 29s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f702f5eaee0>
[ 29s] test_dir = PosixPath('/home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/good_cases')
[ 29s]
[ 29s] @pytest.mark.parametrize(
[ 29s] 'test_dir',
[ 29s] [
[ 29s] 'config_setup',
[ 29s] 'config_tox',
[ 29s] 'config_blue',
[ 29s] 'config_pyproject',
[ 29s] 'good_cases',
[ 29s] ],
[ 29s] )
[ 29s] def test_good_dirs(monkeypatch, test_dir):
[ 29s] test_dir = tests_dir / test_dir
[ 29s] monkeypatch.chdir(test_dir)
[ 29s] monkeypatch.setattr('sys.argv', ['blue', '--check', '.'])
[ 29s] for path in test_dir.rglob('*'):
[ 29s] path.touch() # Invalidate file caches in Blue.
[ 29s] black.find_project_root.cache_clear()
[ 29s] with pytest.raises(SystemExit) as exc_info:
[ 29s] asyncio.set_event_loop(asyncio.new_event_loop())
[ 29s] blue.main()
[ 29s] > assert exc_info.value.code == 0
[ 29s] E assert 123 == 0
[ 29s] E +123
[ 29s] E -0
[ 29s]
[ 29s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/test_blue.py:32: AssertionError
[ 29s] ----------------------------- Captured stderr call -----------------------------
[ 29s] error: cannot format tdq_docstrings.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s] error: cannot format decorators.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s] error: cannot format demo.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s]
[ 29s] Oh no! π₯ π π₯
[ 29s] 3 files would fail to reformat.
[ 29s] ___________________________ test_bad_dirs[bad_cases] ___________________________
[ 29s]
[ 29s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f702f4898e0>
[ 29s] test_dir = PosixPath('/home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/bad_cases')
[ 29s]
[ 29s] @pytest.mark.parametrize(
[ 29s] 'test_dir',
[ 29s] ['bad_cases'],
[ 29s] )
[ 29s] def test_bad_dirs(monkeypatch, test_dir):
[ 29s] test_dir = tests_dir / test_dir
[ 29s] monkeypatch.chdir(test_dir)
[ 29s] monkeypatch.setattr('sys.argv', ['blue', '--check', '.'])
[ 29s] for path in test_dir.rglob('*'):
[ 29s] path.touch() # Invalidate file caches in Blue.
[ 29s] black.find_project_root.cache_clear()
[ 29s] with pytest.raises(SystemExit) as exc_info:
[ 29s] asyncio.set_event_loop(asyncio.new_event_loop())
[ 29s] blue.main()
[ 29s] > assert exc_info.value.code == 1
[ 29s] E assert 123 == 1
[ 29s] E +123
[ 29s] E -1
[ 29s]
[ 29s] /home/abuild/rpmbuild/BUILD/blue-0.8.0/tests/test_blue.py:49: AssertionError
[ 29s] ----------------------------- Captured stderr call -----------------------------
[ 29s] error: cannot format sdq_docstrings.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s] error: cannot format tsq_docstrings.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s] error: cannot format ssq_docstrings.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s] error: cannot format demo.py: list_comments() got an unexpected keyword argument 'preview'
[ 29s]
[ 29s] Oh no! π₯ π π₯
[ 29s] 4 files would fail to reformat.
[ 29s] =========================== short test summary info ============================
[ 29s] FAILED tests/test_blue.py::test_good_dirs[config_setup] - assert 123 == 0
[ 29s] FAILED tests/test_blue.py::test_good_dirs[config_tox] - assert 123 == 0
[ 29s] FAILED tests/test_blue.py::test_good_dirs[config_blue] - assert 123 == 0
[ 29s] FAILED tests/test_blue.py::test_good_dirs[config_pyproject] - assert 123 == 0
[ 29s] FAILED tests/test_blue.py::test_good_dirs[good_cases] - assert 123 == 0
[ 29s] FAILED tests/test_blue.py::test_bad_dirs[bad_cases] - assert 123 == 1
[ 29s] ========================= 6 failed, 2 passed in 0.22s ==========================
[ 29s] error: Bad exit status from /var/tmp/rpm-tmp.JscPCz (%check)
Complete build log with all packages used and steps taken.
What is the most interesting (in my opinion) is that list_comments()
function (if I am not mistaken) own function of this package, so it is strange that tests call it incorrectly. Also, it is strange, that I cannot find the word preview
in the exploded packages.
Whatβs going on, please?
Black went stable, Yaay! Now letβs update to that version and be stable too
Theory is the monkey patching is skipped because reformat_many uses concurrent.futures
When trying to add a setting in setup.cfg
for line-length
, it would be nice to have confirmation that this setting is getting picked up and used during execution of blue
:
$ > git diff
diff --git a/setup.cfg b/setup.cfg
index 5bfb82f..2650e6e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -16,6 +16,9 @@ ignore = E203, E266, E501, W503, PIE781
max-complexity = 12
max-line-length = 100
+[blue]
+line-length = 100
+
[isort]
include_trailing_comma = true
indent = ' '
$ > blue -v src/ test/
src/foobar.egg-info/PKG-INFO ignored: matches the .gitignore file content
src/foobar.egg-info/SOURCES.txt ignored: matches the .gitignore file content
src/foobar.egg-info/requires.txt ignored: matches the .gitignore file content
src/foobar.egg-info/top_level.txt ignored: matches the .gitignore file content
src/foobar.egg-info/dependency_links.txt ignored: matches the .gitignore file content
src/the_company_that_pays_me/foobar/__pycache__/utils.cpython-37.pyc ignored: matches the .gitignore file content
src/the_company_that_pays_me/__pycache__/__init__.cpython-37.pyc ignored: matches the .gitignore file content
test/__pycache__/test_utils.cpython-37-pytest-6.1.2.pyc ignored: matches the .gitignore file content
reformatted /Users/ChrisCarini/code/insights-hub-data_trunk/test/test_utils.py
reformatted /Users/ChrisCarini/code/insights-hub-data_trunk/src/the_company_that_pays_me/foobar/utils.py
All done! β¨ π° β¨
2 files reformatted, 1 files left unchanged.
$ >
See βtanβ at jleclanche/tan@e23c038
There seem to be some arguments around accessibility for supporting tabs.
I was trying to configure blue with a pre-commit hook in my repo.
Unfortunately it doesn't work by simply replacing the black repo with the blue repo (and updating the name and version) in my .pre-commit-config.yaml
. The pre-commit command complains that the blue repo is missing a .pre-commit-hooks.yaml
file.
I think it should be as simple as dropping one that looks like the black one in the top level directory.
Here is the black hooks file:
https://github.com/psf/black/blob/main/.pre-commit-hooks.yaml
This was how I configured my .pre-commit-config.yaml
:
repos:
- repo: https://github.com/grantjenks/blue.git
rev: v0.6.0
hooks:
- id: blue
args:
- -l 120
- -t py38
I tried manually configuring a .pre-commit-hooks.yaml
file in my own repo with the blue id. Not surprisingly, that didn't really help. I'm not quite sure yet how to get blue to run as a pre-commit hook without that file being in the grantjenks/blue repo top level. Suggestions?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.