New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

python-dev-tools

Package Overview
Dependencies
Maintainers
1
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

python-dev-tools - pypi Package Compare versions

Comparing version
2020.9.7
to
2020.9.10
+7
-1
PKG-INFO
Metadata-Version: 2.1
Name: python-dev-tools
Version: 2020.9.7
Version: 2020.9.10
Summary: Needed and up-to-date tools to develop in Python

@@ -204,2 +204,8 @@ Home-page: https://github.com/vpoulailleau/python-dev-tools

2020.9.10
^^^^^^^^^
* The path provided to ``whatalinter`` can be the one of a directory
(recursive search of Python files)
2020.9.7

@@ -206,0 +212,0 @@ ^^^^^^^^

+1
-1
[tool.poetry]
name = "python_dev_tools"
version = "2020.9.7"
version = "2020.9.10"
description = "Needed and up-to-date tools to develop in Python"

@@ -5,0 +5,0 @@ classifiers=[

"""Linter module, aggregation of linters."""
import argparse
import contextlib
import io
import os
import pathlib
import re
import sys
from pathlib import Path
from typing import List, Optional, Union
from python_dev_tools.linters.common import DEFAULT_MESSAGE_FORMAT
from python_dev_tools.linters.lint import lint
from flake8.main import application
DEFAULT_MESSAGE_TEMPLATE = "%(path)s:%(row)d:%(col)d: %(code)s %(text)s"
def udpate_os_path():
"""Update PATH env variable to find linters."""
script_path = pathlib.Path(__file__).resolve()
os.environ["PATH"] = "".join(
(str(script_path.parent), os.pathsep, os.environ["PATH"]),
path_var_name = "PATH"
script_path = Path(__file__).resolve()
os.environ[path_var_name] = "".join(
(str(script_path.parent), os.pathsep, os.environ[path_var_name]),
)

@@ -20,7 +27,100 @@

if parent.stem == "lib":
os.environ["PATH"] = "".join(
(str(parent.parent / "bin"), os.pathsep, os.environ["PATH"]),
os.environ[path_var_name] = "".join(
(str(parent.parent / "bin"), os.pathsep, os.environ[path_var_name]),
)
def _call_flake8(argv: Optional[List[str]] = None) -> None:
"""Execute the main bit of the application.
This handles the creation of an instance of the class `Application`, runs it,
and then exits the application.
Args:
argv (Optional[List[str]]): The arguments to be passed to the application for
parsing.
"""
if argv is None:
argv = sys.argv[1:]
app = application.Application()
app.run(argv)
app.exit()
def _run_flake8(path: Path) -> str:
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
try:
_call_flake8(
[
str(path),
"--exit-zero",
"--max-line-length",
"88",
"--max-complexity",
"10",
"--inline-quotes",
'"',
# E203: space around : in slice
# WPS305: avoid f-strings
# WPS306: required explicit subclassing of object
# WPS602: avoid @staticmethod (can be subclassed…)
"--ignore=E203,WPS305,WPS306,WPS602",
],
)
except SystemExit:
pass # TODO what do we do here?
return stdout.getvalue()
def _filter_out(message: str) -> bool:
"""Return True when message should be ignored.
Args:
message (str): message to analyze
Returns:
bool: True when message should be ignored, False otherwise
"""
for authorized_function in ("input", "print", "pprint"):
if f"Found wrong function call: {authorized_function}" in message:
return True
return False
def _add_info(message: str) -> str:
# TODO
return message
def _format(message: str, template: str) -> str:
regex = r"(?P<path>.*?):(?P<row>\d+):(?P<col>\d+):\s+(?P<code>.*?)\s+(?P<text>.*)"
match = re.match(regex, message)
if match:
infos = match.groupdict()
infos["row"] = int(infos["row"])
infos["col"] = int(infos["col"])
message = template % infos
else:
print("ERROR parsing:", message)
return message
def lint(path: Union[str, Path], template: str = DEFAULT_MESSAGE_TEMPLATE) -> None:
"""Lint a file or a directory according to its path.
Args:
path (Union[str, Path]): path of the file or directory
template (str): template of linter message
"""
flake8_result = _run_flake8(path)
for message in flake8_result.splitlines():
if _filter_out(message):
continue
message = _add_info(message)
print(_format(message, template))
def main():

@@ -32,19 +132,17 @@ """Entry point."""

parser.add_argument(
"file", metavar="FILE", type=str, help="path of the file to lint",
"path",
metavar="PATH",
type=str,
help="path of the file or directory to lint",
)
parser.add_argument(
"-f", "--format", default=DEFAULT_MESSAGE_FORMAT, help="format of the output",
"-f",
"--format",
default=DEFAULT_MESSAGE_TEMPLATE,
help="format of the output",
)
parser.add_argument(
"-a",
"--all",
action="store_true",
default=False,
help="display all warnings (default: display first ten warnings)",
)
args = parser.parse_args()
udpate_os_path()
for message in lint(filepath=args.file, all_warnings=args.all):
print(message.formatted(args.format))
lint(path=args.path, template=args.format)

@@ -51,0 +149,0 @@

@@ -141,2 +141,8 @@ Python Dev Tools

2020.9.10
^^^^^^^^^
* The path provided to ``whatalinter`` can be the one of a directory
(recursive search of Python files)
2020.9.7

@@ -143,0 +149,0 @@ ^^^^^^^^

@@ -5,3 +5,3 @@ # -*- coding: utf-8 -*-

packages = \
['python_dev_tools', 'python_dev_tools.formatters', 'python_dev_tools.linters']
['python_dev_tools', 'python_dev_tools.formatters']

@@ -58,5 +58,5 @@ package_data = \

'name': 'python-dev-tools',
'version': '2020.9.7',
'version': '2020.9.10',
'description': 'Needed and up-to-date tools to develop in Python',
'long_description': 'Python Dev Tools\n================\n\nNeeded and up-to-date tools to develop in Python (*WORK IN PROGRESS*)\n\n\n.. image:: https://img.shields.io/pypi/v/python_dev_tools.svg\n :target: https://pypi.python.org/pypi/python_dev_tools\n\n.. image:: https://img.shields.io/pypi/l/python_dev_tools.svg\n :target: https://github.com/vpoulailleau/python_dev_tools/blob/master/LICENSE\n\n.. image:: https://travis-ci.com/vpoulailleau/python-dev-tools.svg?branch=master\n :target: https://travis-ci.com/vpoulailleau/python-dev-tools\n\n.. image:: https://readthedocs.org/projects/python-dev-tools/badge/?version=latest\n :target: https://python-dev-tools.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\n.. image:: https://pepy.tech/badge/python-dev-tools\n :target: https://pepy.tech/project/python-dev-tools\n :alt: Downloads\n\n.. image:: https://api.codeclimate.com/v1/badges/282fcd71714dabd6a847/test_coverage\n :target: https://codeclimate.com/github/vpoulailleau/python-dev-tools/test_coverage\n :alt: Test Coverage\n\n.. image:: https://api.codeclimate.com/v1/badges/282fcd71714dabd6a847/maintainability\n :target: https://codeclimate.com/github/vpoulailleau/python-dev-tools/maintainability\n :alt: Maintainability\n\n.. image:: https://bettercodehub.com/edge/badge/vpoulailleau/python-dev-tools?branch=master\n :target: https://bettercodehub.com/results/vpoulailleau/python-dev-tools\n :alt: Maintainability\n\n.. image:: https://img.shields.io/lgtm/grade/python/g/vpoulailleau/python-dev-tools.svg?logo=lgtm&logoWidth=1\n :target: https://lgtm.com/projects/g/vpoulailleau/python-dev-tools/context:python\n :alt: Maintainability\n\nDocumentation\n-------------\n\nThe full documentation can be read at https://python-dev-tools.readthedocs.io.\n\nInstallation\n------------\n\nIn a terminal, run:\n\n.. code-block:: console\n\n $ python3 -m pip install python-dev-tools --user --upgrade\n\nFull documentation on installation: https://python-dev-tools.readthedocs.io/en/latest/installation.html\n\nThat\'s it! Use the provided linter (``whatalinter``), formatter (``whataformatter``) and\nprecommit hook (TODO) where applicable.\n\nInstallation with Visual Studio Code\n------------------------------------\n\n* Follow the installation procedure for python-dev-tools\n* Be sure to have the official Python extension installed in VS Code\n* Open VS Code from within your activated virtual environment (in fact, make sure that \n ``whatalinter_vscode`` is in your ``PYTHON_PATH``)\n* In VS Code, open settings (F1 key, then type "Open Settings (JSON)",\n then enter)\n* Add in the opened JSON file (before the closing ``}``):\n\n.. code:: javascript\n\n "python.linting.enabled": true,\n "python.linting.flake8Enabled": true,\n "python.linting.flake8Path": "whatalinter_vscode",\n "python.formatting.provider": "black",\n "python.formatting.blackPath": "black",\n "python.formatting.blackArgs": [],\n\nFeatures\n--------\n\nIntegrate features of commonly used tools. This package provides usual\ndependencies to develop Python software.\n\n* Simple linter\n\n * ``whatalinter a_python_file.py`` lints a_python_file.py\n * output is compatible with the one of flake8 for easy integration in text editors\n and IDE\n * based on flake8 and plugins: https://gitlab.com/pycqa/flake8\n\n * darglint: https://github.com/terrencepreilly/darglint\n * flake8-2020: https://github.com/asottile/flake8-2020\n * flake8-bandit: https://github.com/tylerwince/flake8-bandit\n * flake8-broken-line: https://github.com/sobolevn/flake8-broken-line\n * flake8-bugbear: https://github.com/PyCQA/flake8-bugbear\n * flake8-builtins: https://github.com/gforcada/flake8-builtins\n * flake8-commas: https://github.com/PyCQA/flake8-commas/\n * flake8-comprehensions: https://github.com/adamchainz/flake8-comprehensions\n * flake8-debugger: https://github.com/JBKahn/flake8-debugger\n * flake8-docstrings: https://gitlab.com/pycqa/flake8-docstrings\n * flake8-eradicate: https://github.com/sobolevn/flake8-eradicate\n * flake8-fixme: https://github.com/tommilligan/flake8-fixme\n * flake8-isort: https://github.com/gforcada/flake8-isort\n * flake8-logging-format: https://github.com/globality-corp/flake8-logging-format\n * flake8-mutable: https://github.com/ebeweber/flake8-mutable\n * flake8-quotes: https://github.com/zheller/flake8-quotes/\n * flake8-rst-docstrings: https://github.com/peterjc/flake8-rst-docstrings\n * flake8-string-format: https://github.com/xZise/flake8-string-format\n * flake8-variables-names: https://github.com/best-doctor/flake8-variables-names\n * pep8-naming: https://github.com/PyCQA/pep8-naming\n * wemake-python-styleguide: https://github.com/wemake-services/wemake-python-styleguide\n\n* Simple formatter\n\n * ``whataformatter a_python_file.py`` formats a_python_file.py\n * based on\n\n * autoflake: https://github.com/myint/autoflake\n * black: https://github.com/python/black\n * pyupgrade: https://github.com/asottile/pyupgrade\n\n* Simple precommit hook\n\n * TODO\n\nLicense\n-------\n\nBSD 3-Clause license, feel free to contribute: https://python-dev-tools.readthedocs.io/en/latest/contributing.html.\n\nTODO\n----\n\n* documentation\n* precommit\n\nChangelog\n---------\n\n2020.9.7\n^^^^^^^^\n\n* Remove E203 in ``flake8`` for ``black`` compatibility\n\n2020.9.4\n^^^^^^^^\n\n* Add ``whatalinter_vscode`` for Visual Studio Code integration\n\n2020.9.2\n^^^^^^^^\n\n* Remove some warnings of ``wemake-python-styleguide``, for instance allow f-strings\n\n2020.9.1\n^^^^^^^^\n\n* Use ``poetry``\n* Remove redundant linters\n* Change max line length to 88 (default value of ``black``)\n* Replace ``pydocstyle`` with ``flake8-docstrings``\n* Add ``wemake-python-styleguide``\n\n2019.10.22\n^^^^^^^^^^\n\n* Add ``flake8-2020`` linter\n\n2019.07.21\n^^^^^^^^^^\n\n* Add ``--quiet`` and ``--diff`` flags to ``whataformatter`` for VS Code compatibility\n\n2019.07.20\n^^^^^^^^^^\n\n* Add ``black`` formatter\n* Add ``autoflake`` formatter\n* Add ``pyupgrade`` formatter\n\n2019.04.08\n^^^^^^^^^^\n\n* Add ``flake8`` linter\n* Add ``flake8-isort`` linter\n* Add ``pep8-naming`` linter\n* Add ``flake8-comprehensions`` linter\n* Add ``flake8-logging-format`` linter\n* Add ``flake8-bugbear`` linter\n* Add ``flake8-builtins`` linter\n* Add ``flake8-broken-line`` linter\n* Add ``flake8-fixme`` linter\n* Add ``flake8-mutable`` linter\n* Add ``flake8-debugger`` linter\n* Add ``flake8-variables-names`` linter\n* Add ``flake8-bandit`` linter\n\n2019.03.02\n^^^^^^^^^^\n\n* Add ``pydocstyle`` linter\n\n2019.03.01\n^^^^^^^^^^\n\n* Add McCabe complexity checker\n\n2019.02.26\n^^^^^^^^^^\n\n* Add ``pyflakes`` linter\n* Add ``pycodestyle`` linter\n\n2019.02.23\n^^^^^^^^^^\n\n* First release on PyPI.\n',
'long_description': 'Python Dev Tools\n================\n\nNeeded and up-to-date tools to develop in Python (*WORK IN PROGRESS*)\n\n\n.. image:: https://img.shields.io/pypi/v/python_dev_tools.svg\n :target: https://pypi.python.org/pypi/python_dev_tools\n\n.. image:: https://img.shields.io/pypi/l/python_dev_tools.svg\n :target: https://github.com/vpoulailleau/python_dev_tools/blob/master/LICENSE\n\n.. image:: https://travis-ci.com/vpoulailleau/python-dev-tools.svg?branch=master\n :target: https://travis-ci.com/vpoulailleau/python-dev-tools\n\n.. image:: https://readthedocs.org/projects/python-dev-tools/badge/?version=latest\n :target: https://python-dev-tools.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\n.. image:: https://pepy.tech/badge/python-dev-tools\n :target: https://pepy.tech/project/python-dev-tools\n :alt: Downloads\n\n.. image:: https://api.codeclimate.com/v1/badges/282fcd71714dabd6a847/test_coverage\n :target: https://codeclimate.com/github/vpoulailleau/python-dev-tools/test_coverage\n :alt: Test Coverage\n\n.. image:: https://api.codeclimate.com/v1/badges/282fcd71714dabd6a847/maintainability\n :target: https://codeclimate.com/github/vpoulailleau/python-dev-tools/maintainability\n :alt: Maintainability\n\n.. image:: https://bettercodehub.com/edge/badge/vpoulailleau/python-dev-tools?branch=master\n :target: https://bettercodehub.com/results/vpoulailleau/python-dev-tools\n :alt: Maintainability\n\n.. image:: https://img.shields.io/lgtm/grade/python/g/vpoulailleau/python-dev-tools.svg?logo=lgtm&logoWidth=1\n :target: https://lgtm.com/projects/g/vpoulailleau/python-dev-tools/context:python\n :alt: Maintainability\n\nDocumentation\n-------------\n\nThe full documentation can be read at https://python-dev-tools.readthedocs.io.\n\nInstallation\n------------\n\nIn a terminal, run:\n\n.. code-block:: console\n\n $ python3 -m pip install python-dev-tools --user --upgrade\n\nFull documentation on installation: https://python-dev-tools.readthedocs.io/en/latest/installation.html\n\nThat\'s it! Use the provided linter (``whatalinter``), formatter (``whataformatter``) and\nprecommit hook (TODO) where applicable.\n\nInstallation with Visual Studio Code\n------------------------------------\n\n* Follow the installation procedure for python-dev-tools\n* Be sure to have the official Python extension installed in VS Code\n* Open VS Code from within your activated virtual environment (in fact, make sure that \n ``whatalinter_vscode`` is in your ``PYTHON_PATH``)\n* In VS Code, open settings (F1 key, then type "Open Settings (JSON)",\n then enter)\n* Add in the opened JSON file (before the closing ``}``):\n\n.. code:: javascript\n\n "python.linting.enabled": true,\n "python.linting.flake8Enabled": true,\n "python.linting.flake8Path": "whatalinter_vscode",\n "python.formatting.provider": "black",\n "python.formatting.blackPath": "black",\n "python.formatting.blackArgs": [],\n\nFeatures\n--------\n\nIntegrate features of commonly used tools. This package provides usual\ndependencies to develop Python software.\n\n* Simple linter\n\n * ``whatalinter a_python_file.py`` lints a_python_file.py\n * output is compatible with the one of flake8 for easy integration in text editors\n and IDE\n * based on flake8 and plugins: https://gitlab.com/pycqa/flake8\n\n * darglint: https://github.com/terrencepreilly/darglint\n * flake8-2020: https://github.com/asottile/flake8-2020\n * flake8-bandit: https://github.com/tylerwince/flake8-bandit\n * flake8-broken-line: https://github.com/sobolevn/flake8-broken-line\n * flake8-bugbear: https://github.com/PyCQA/flake8-bugbear\n * flake8-builtins: https://github.com/gforcada/flake8-builtins\n * flake8-commas: https://github.com/PyCQA/flake8-commas/\n * flake8-comprehensions: https://github.com/adamchainz/flake8-comprehensions\n * flake8-debugger: https://github.com/JBKahn/flake8-debugger\n * flake8-docstrings: https://gitlab.com/pycqa/flake8-docstrings\n * flake8-eradicate: https://github.com/sobolevn/flake8-eradicate\n * flake8-fixme: https://github.com/tommilligan/flake8-fixme\n * flake8-isort: https://github.com/gforcada/flake8-isort\n * flake8-logging-format: https://github.com/globality-corp/flake8-logging-format\n * flake8-mutable: https://github.com/ebeweber/flake8-mutable\n * flake8-quotes: https://github.com/zheller/flake8-quotes/\n * flake8-rst-docstrings: https://github.com/peterjc/flake8-rst-docstrings\n * flake8-string-format: https://github.com/xZise/flake8-string-format\n * flake8-variables-names: https://github.com/best-doctor/flake8-variables-names\n * pep8-naming: https://github.com/PyCQA/pep8-naming\n * wemake-python-styleguide: https://github.com/wemake-services/wemake-python-styleguide\n\n* Simple formatter\n\n * ``whataformatter a_python_file.py`` formats a_python_file.py\n * based on\n\n * autoflake: https://github.com/myint/autoflake\n * black: https://github.com/python/black\n * pyupgrade: https://github.com/asottile/pyupgrade\n\n* Simple precommit hook\n\n * TODO\n\nLicense\n-------\n\nBSD 3-Clause license, feel free to contribute: https://python-dev-tools.readthedocs.io/en/latest/contributing.html.\n\nTODO\n----\n\n* documentation\n* precommit\n\nChangelog\n---------\n\n2020.9.10\n^^^^^^^^^\n\n* The path provided to ``whatalinter`` can be the one of a directory\n (recursive search of Python files)\n\n2020.9.7\n^^^^^^^^\n\n* Remove E203 in ``flake8`` for ``black`` compatibility\n\n2020.9.4\n^^^^^^^^\n\n* Add ``whatalinter_vscode`` for Visual Studio Code integration\n\n2020.9.2\n^^^^^^^^\n\n* Remove some warnings of ``wemake-python-styleguide``, for instance allow f-strings\n\n2020.9.1\n^^^^^^^^\n\n* Use ``poetry``\n* Remove redundant linters\n* Change max line length to 88 (default value of ``black``)\n* Replace ``pydocstyle`` with ``flake8-docstrings``\n* Add ``wemake-python-styleguide``\n\n2019.10.22\n^^^^^^^^^^\n\n* Add ``flake8-2020`` linter\n\n2019.07.21\n^^^^^^^^^^\n\n* Add ``--quiet`` and ``--diff`` flags to ``whataformatter`` for VS Code compatibility\n\n2019.07.20\n^^^^^^^^^^\n\n* Add ``black`` formatter\n* Add ``autoflake`` formatter\n* Add ``pyupgrade`` formatter\n\n2019.04.08\n^^^^^^^^^^\n\n* Add ``flake8`` linter\n* Add ``flake8-isort`` linter\n* Add ``pep8-naming`` linter\n* Add ``flake8-comprehensions`` linter\n* Add ``flake8-logging-format`` linter\n* Add ``flake8-bugbear`` linter\n* Add ``flake8-builtins`` linter\n* Add ``flake8-broken-line`` linter\n* Add ``flake8-fixme`` linter\n* Add ``flake8-mutable`` linter\n* Add ``flake8-debugger`` linter\n* Add ``flake8-variables-names`` linter\n* Add ``flake8-bandit`` linter\n\n2019.03.02\n^^^^^^^^^^\n\n* Add ``pydocstyle`` linter\n\n2019.03.01\n^^^^^^^^^^\n\n* Add McCabe complexity checker\n\n2019.02.26\n^^^^^^^^^^\n\n* Add ``pyflakes`` linter\n* Add ``pycodestyle`` linter\n\n2019.02.23\n^^^^^^^^^^\n\n* First release on PyPI.\n',
'author': 'Vincent Poulailleau',

@@ -63,0 +63,0 @@ 'author_email': 'vpoulailleau@gmail.com',

"""Common constants and class to all linters."""
import re
import subprocess
from functools import total_ordering
DEFAULT_MESSAGE_FORMAT = "%(path)s:%(row)d:%(col)d: %(code)s %(text)s"
# TODO use dataclass
@total_ordering
class LinterMessage:
"""Generic linter message."""
def __init__(
self,
tool="unknown",
message_id="unknown",
filename="unknown",
lineno=1,
charno=1,
message="unknown",
extramessage="",
):
"""Initialize the new instance."""
self.tool = tool
self.message_id = message_id
self.filename = filename
self.lineno = lineno
self.charno = charno
self.message = message
self.extramessage = extramessage
def __repr__(self):
"""Represent as a string."""
return self.formatted(DEFAULT_MESSAGE_FORMAT)
def as_tuple(self):
"""Represent as a tuple for identification."""
return (
self.filename,
self.lineno,
self.charno,
self.tool,
self.message_id,
self.message,
self.message_id,
)
def __lt__(self, other):
"""Test less than."""
return self.as_tuple() < other.as_tuple()
def __eq__(self, other):
"""Test equality."""
return self.as_tuple() == other.as_tuple()
def __hash__(self):
"""Compute hash."""
return hash(self.as_tuple())
def formatted(self, format_string):
"""Format the message according to format parameter."""
data = {
"path": self.filename,
"row": self.lineno if self.lineno else 1,
"col": self.charno,
"code": f"{self.message_id}",
"text": f"[{self.tool}] {self.message}",
}
if self.extramessage:
data["text"] += f" ({self.extramessage})"
return format_string % data
class LinterNotFound(FileNotFoundError):
"""
Exception to detect that a linter is not found.
Note that this doesn't occur, except due to an installation error.
"""
class Linter:
"""Base linter class."""
name = "Linter"
path = "/bin/unknownlinter"
regex = [".*"]
@classmethod
def lint(cls, filepath):
"""Execute the linter and return the list of messages."""
try:
return cls._lint(filepath)
except LinterNotFound:
return [
LinterMessage(
tool="whatalinter",
message_id="E999",
filename=str(filepath),
lineno=1,
charno=1,
message=f"linter not found: {cls.path}",
extramessage="",
)
]
@classmethod
def _lint(cls, filepath):
args = [cls.path, str(filepath)]
result = cls._execute_command(args)
return cls._parse_output(result.stdout)
@classmethod
def _execute_command(cls, args):
"""Execute the linter or raise LinterNotFound."""
try:
return subprocess.run( # noqa: S603
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
encoding="utf-8",
)
except FileNotFoundError as e:
if e.filename == cls.path:
raise LinterNotFound
else:
raise
@classmethod
def _parse_line(cls, line, regex, message=None, **kwargs):
match = re.match(regex, line)
if match:
if not message:
message = LinterMessage()
kwargs.update(match.groupdict())
if "lineno" in kwargs:
kwargs["lineno"] = int(kwargs["lineno"])
if "charno" in kwargs:
kwargs["charno"] = int(kwargs["charno"])
for param, value in kwargs.items():
setattr(message, param, value)
else:
print("ERROR parsing:", line)
return message
@classmethod
def _parse_output(cls, output):
messages = []
message = None
regex_index = 0
for line in output.splitlines():
message = cls._parse_line(
line, cls.regex[regex_index], message, tool=cls.name,
)
if isinstance(message, LinterMessage):
if regex_index == len(cls.regex) - 1:
regex_index = 0
if not cls.filter_out(message):
messages.append(message)
message = None
else:
regex_index += 1
return messages
@staticmethod
def filter_out(message: LinterMessage) -> bool:
"""Return True when message should be ignored."""
return False
"""Flake8 linter management."""
import contextlib
import io
from flake8.main.cli import main
from python_dev_tools.linters.common import Linter, LinterMessage
class Flake8Linter(Linter):
"""Pycodestyle linter management."""
name = "flake8"
path = "flake8"
regex = [
(
r"(?P<filename>.*?):(?P<lineno>\d+):(?P<charno>\d+):"
+ r"\s+(?P<message_id>.*?)\s+(?P<message>.*)"
),
]
@classmethod
def _lint(cls, filepath):
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
try:
main(
[
str(filepath),
"--exit-zero",
"--max-line-length",
"88",
"--max-complexity",
"10",
"--inline-quotes",
'"',
# E203: space around : in slice
# WPS305: avoid f-strings
# WPS306: required explicit subclassing of object
# WPS602: avoid @staticmethod (can be subclassed…)
"--ignore=E203,WPS305,WPS306,WPS602",
],
)
except SystemExit:
# TODO what do we do here?
pass
return cls._parse_output(stdout.getvalue())
@staticmethod
def filter_out(message: LinterMessage) -> bool:
"""Return True when message should be ignored."""
for authorized_function in ("input", "print", "pprint"):
if f"Found wrong function call: {authorized_function}" in message.message:
return True
return False
"""Definition of lint function, calling all linters."""
from python_dev_tools.linters.flake8 import Flake8Linter
linters = [
Flake8Linter,
]
def lint(filepath, all_warnings=False):
"""Lint the file with known linters."""
messages = set()
for linter in linters:
messages.update(linter.lint(filepath))
if len(messages) >= 10 and not all_warnings:
break
messages = sorted(messages)
if all_warnings:
return messages
return messages[:10]