wemake-services/wemake-python-styleguide

WPS508 on negating chain comparison

Xoriun opened this issue · 4 comments

What's wrong

For the code

a = 6

if not (4 < a <= 6):
    print('hey')

I get an WPS508 on the not in the condition.

How it should be

However, there is no way to rewrite the expression without not and still using chain comparison and therefore I don't think that WPS508 should be raised on negated chain comparisons.

Flake8 version and plugins

{
"platform": {
"python_implementation": "CPython",
"python_version": "3.11.6",
"system": "Windows"
},
"plugins": [
{
"plugin": "darglint",
"version": "1.8.1"
},
{
"plugin": "flake8-bandit",
"version": "4.1.1"
},
{
"plugin": "flake8-broken-line",
"version": "1.0.0"
},
{
"plugin": "flake8-bugbear",
"version": "24.2.6"
},
{
"plugin": "flake8-builtins",
"version": "2.2.0"
},
{
"plugin": "flake8-commas",
"version": "2.1.0"
},
{
"plugin": "flake8-comprehensions",
"version": "3.14.0"
},
{
"plugin": "flake8-debugger",
"version": "4.1.2"
},
{
"plugin": "flake8-docstrings",
"version": "1.7.0"
},
{
"plugin": "flake8-eradicate",
"version": "1.5.0"
},
{
"plugin": "flake8-isort",
"version": "6.1.1"
},
{
"plugin": "flake8-pie",
"version": "0.16.0"
},
{
"plugin": "flake8-quotes",
"version": "3.4.0"
},
{
"plugin": "flake8-rst-docstrings",
"version": "0.3.0"
},
{
"plugin": "flake8-string-format",
"version": "0.3.0"
},
{
"plugin": "mccabe",
"version": "0.7.0"
},
{
"plugin": "pep8-naming",
"version": "0.13.3"
},
{
"plugin": "pycodestyle",
"version": "2.11.1"
},
{
"plugin": "pyflakes",
"version": "3.2.0"
},
{
"plugin": "wemake-python-styleguide",
"version": "0.19.0"
}
],
"version": "7.0.0"
}

pip information

pip 24.0 from C:\Users~~\AppData\Local\Programs\Python\Python311\Lib\site-packages\pip (python 3.11)
aiofiles==23.2.1
alabaster==0.7.16
altgraph==0.17.4
annotated-types==0.6.0
anyio==4.3.0
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
arrow==1.3.0
astor==0.8.1
astroid==3.1.0
asttokens==2.4.1
async-lru==2.0.4
attrs==23.2.0
auto-py-to-exe==2.43.3
autocommand==2.2.2
Babel==2.14.0
bandit==1.7.8
bashlex==0.18
beautifulsoup4==4.12.3
bleach==6.1.0
bottle==0.12.25
bottle-websocket==0.2.9
bracex==2.4
certifi==2024.2.2
cffi==1.16.0
chardet==5.2.0
charset-normalizer==3.3.2
ci-info==0.3.0
cibuildwheel==2.17.0
click==8.1.7
cmake==3.28.4
colorama==0.4.6
comm==0.2.2
configobj==5.0.8
configparser==6.0.1
contourpy==1.2.0
coverage==7.4.4
cycler==0.12.1
Cython==3.0.9
darglint==1.8.1
debugpy==1.8.1
decorator==5.1.1
defusedxml==0.7.1
dill==0.3.8
distro==1.9.0
docutils==0.20.1
Eel==0.16.0
eradicate==2.3.0
etelemetry==0.3.1
executing==2.0.1
fastjsonschema==2.19.1
filelock==3.13.3
flake8==7.0.0
flake8-bandit==4.1.1
flake8-broken-line==1.0.0
flake8-bugbear==24.2.6
flake8-builtins==2.2.0
flake8-commas==2.1.0
flake8-comprehensions==3.14.0
flake8-debugger==4.1.2
flake8-docstrings==1.7.0
flake8-eradicate==1.5.0
flake8-isort==6.1.1
flake8-pie==0.16.0
flake8-quotes==3.4.0
flake8-rst-docstrings==0.3.0
flake8-string-format==0.3.0
fonttools==4.50.0
fqdn==1.5.1
frontend==0.0.3
future==1.0.0
gevent==24.2.1
gevent-websocket==0.10.1
gitdb==4.0.11
GitPython==3.1.42
greenlet==3.0.3
gudhi==3.9.0
h11==0.14.0
httpcore==1.0.4
httplib2==0.22.0
httpx==0.27.0
idna==3.6
imagesize==1.4.1
inflect==7.0.0
iniconfig==2.0.0
ipykernel==6.29.3
ipympl==0.9.3
ipython==8.22.2
ipython-genutils==0.2.0
ipywidgets==8.1.2
iso8601==2.1.0
isodate==0.6.1
isoduration==20.11.0
isort==5.13.2
itsdangerous==2.1.2
jaraco.classes==3.3.1
jaraco.collections==5.0.0
jaraco.context==4.3.0
jaraco.functools==4.0.0
jaraco.structures==2.2.0
jaraco.text==3.12.0
jaraco.ui==2.3.0
jaraco.windows==5.8.0
jedi==0.19.1
Jinja2==3.1.3
json5==0.9.24
jsonpointer==2.4
jsonschema==4.21.1
jsonschema-specifications==2023.12.1
jupyter-events==0.10.0
jupyter-lsp==2.2.4
jupyter_client==8.6.1
jupyter_core==5.7.2
jupyter_server==2.13.0
jupyter_server_terminals==0.5.3
jupyterlab==4.1.5
jupyterlab_pygments==0.3.0
jupyterlab_server==2.25.4
jupyterlab_widgets==3.0.10
kiwisolver==1.4.5
line-profiler==4.1.2
looseversion==1.3.0
lxml==5.1.0
markdown-it-py==3.0.0
MarkupSafe==2.1.5
matplotlib==3.8.3
matplotlib-inline==0.1.6
mccabe==0.7.0
mdurl==0.1.2
mistune==3.0.2
more-itertools==10.2.0
nbclient==0.10.0
nbconvert==7.16.3
nbformat==5.10.3
nest-asyncio==1.6.0
networkx==3.2.1
nibabel==5.2.1
ninja==1.11.1.1
nipype==1.8.6
notebook==7.1.2
notebook_shim==0.2.4
numpy==1.26.4
overrides==7.7.0
packaging==24.0
pandas==2.2.1
pandocfilters==1.5.1
parso==0.8.3
path==16.10.0
pathlib==1.0.1
pbr==6.0.0
pefile==2023.2.7
pep8-naming==0.13.3
pillow==10.2.0
platformdirs==4.2.0
plotly==5.20.0
pluggy==1.4.0
prometheus_client==0.20.0
prompt-toolkit==3.0.43
prov==2.0.0
psutil==5.9.8
pure-eval==0.2.2
pyasn1==0.5.1
pycodestyle==2.11.1
pycparser==2.21
pydantic==2.6.4
pydantic_core==2.16.3
pydocstyle==6.3.0
pydot==2.0.0
pyflakes==3.2.0
Pygments==2.17.2
pyinstaller==6.5.0
pyinstaller-hooks-contrib==2024.3
pylint==3.1.0
PyMuPDF==1.24.0
PyMuPDFb==1.24.0
pyparsing==3.1.2
pyserial==3.5
PySimpleGUIWeb==0.39.0
pytest==8.1.1
pytest-cov==5.0.0
python-dateutil==2.9.0.post0
python-json-logger==2.0.7
pytz==2024.1
pywin32==306
pywin32-ctypes==0.2.2
pywinpty==2.0.13
pyxnat==1.6.2
PyYAML==6.0.1
pyzmq==25.1.2
rdflib==7.0.0
referencing==0.34.0
remi==2022.7.27
reportlab==4.1.0
requests==2.31.0
restructuredtext-lint==1.4.0
rfc3339-validator==0.1.4
rfc3986-validator==0.1.1
rich==13.7.1
rpds-py==0.18.0
rsa==4.9
scikit-build==0.17.6
scipy==1.12.0
Send2Trash==1.8.2
simplejson==3.19.2
six==1.16.0
smmap==5.0.1
sniffio==1.3.1
snowballstemmer==2.2.0
soupsieve==2.5
Sphinx==7.2.6
sphinxcontrib-applehelp==1.0.8
sphinxcontrib-devhelp==1.0.6
sphinxcontrib-htmlhelp==2.0.5
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.7
sphinxcontrib-serializinghtml==1.1.10
stack-data==0.6.3
starlette==0.37.2
stevedore==5.2.0
tenacity==8.2.3
terminado==0.18.1
tinycss2==1.2.1
tomlkit==0.12.4
tornado==6.4
traitlets==5.14.2
traits==6.4.3
types-python-dateutil==2.9.0.20240316
typing_extensions==4.10.0
tzdata==2024.1
ubelt==1.3.5
uri-template==1.3.0
urllib3==2.2.1
uvicorn==0.29.0
wcwidth==0.2.13
webcolors==1.13
webencodings==0.5.1
websocket-client==1.7.0
wemake-python-styleguide==0.19.0
whichcraft==0.6.1
widgetsnbextension==4.0.10
wxPython==4.2.1
xdoctest==1.1.3
zope.event==5.0
zope.interface==6.2

OS information

Windows 10

if a > 6 or a <= 4: :)

Yes, but that's not a chain condition, which is the whole point of this report.

Forbid not with compare expressions.

This is exactly what this rule does. Or am I missing something? :)

This rule forbids something like if not a < b since it can be rewritten as if a >= b. Here, the second version is clearly more readable which is (as I understand it) the reason for the rule - readability.
But for chain comparisons like if not a < b < c there is no way to rewrite it without not but still maintaining the chain comparison. Removing not leads to something like if a >=b or b >= c which (at least for me) is quite a lot less readable than what I had before. I would be fine with negated chain comparisons needing parentacise around them like if not (a < b < c).