diff --git a/foxylint/loggingcase.py b/foxylint/loggingcase.py new file mode 100644 index 0000000..04334f2 --- /dev/null +++ b/foxylint/loggingcase.py @@ -0,0 +1,38 @@ +import re + + +class _AnalyzeFile: + def __init__(self, file): + self._file = file + self._go() + + def _go(self): + BAD_PATTERN = re.compile(r"""(logging|logger)\.(info|warning|error|debug|critical)\(["'][A-Z]""") + errors = [] + with open(self._file) as f: + for line_number, line in enumerate(f, start=1): + match = BAD_PATTERN.search(line) + if match is not None: + if self._acceptable(line): + continue + errors.append({'line_number': line_number, 'line_content': line.strip()}) + ok = len(errors) == 0 + self._result = {'ok': ok, 'errors': errors} + + def _acceptable(self, line): + if self._comment(line): + return True + IGNORE_PATTERN = re.compile(r'#\s*foxylint-loggingcase:ignore\s*$') + return IGNORE_PATTERN.search(line) is not None + + def _comment(self, line): + return line.strip().startswith('#') + + @property + def result(self): + return self._result + + +def analyze(files): + analyses = {file: _AnalyzeFile(file).result for file in files} + return analyses diff --git a/poetry.lock b/poetry.lock index c00fa04..f335e29 100644 --- a/poetry.lock +++ b/poetry.lock @@ -664,6 +664,41 @@ pluggy = ">=1.5,<2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "python-box" +version = "7.2.0" +description = "Advanced Python dictionaries with dot notation access" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python_box-7.2.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:6bdeec791e25258351388b3029a3ec5da302bb9ed3be175493c43cdc6c47f5e3"}, + {file = "python_box-7.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c449f7b3756a71479fa9c61a86e344ac00ed782a66d7662590f0afa294249d18"}, + {file = "python_box-7.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:6b0d61f182d394106d963232854e495b51edc178faa5316a797be1178212d7e0"}, + {file = "python_box-7.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e2d752de8c1204255bf7b0c814c59ef48293c187a7e9fdcd2fefa28024b72032"}, + {file = "python_box-7.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a6c35ea356a386077935958a5debcd5b229b9a1b3b26287a52dfe1a7e65d99"}, + {file = "python_box-7.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:32ed58ec4d9e5475efe69f9c7d773dfea90a6a01979e776da93fd2b0a5d04429"}, + {file = "python_box-7.2.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a2d664c6a27f7515469b6f1e461935a2038ee130b7d194b4b4db4e85d363618"}, + {file = "python_box-7.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5a7365db1aaf600d3e8a2747fcf6833beb5d45439a54318548f02e302e3ec"}, + {file = "python_box-7.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:739f827056ea148cbea3122d4617c994e829b420b1331183d968b175304e3a4f"}, + {file = "python_box-7.2.0-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:2617ef3c3d199f55f63c908f540a4dc14ced9b18533a879e6171c94a6a436f23"}, + {file = "python_box-7.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffd866bed03087b1d8340014da8c3aaae19135767580641df1b4ae6fff6ac0aa"}, + {file = "python_box-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:9681f059e7e92bdf20782cd9ea6e533d4711fc7b8c57a462922a025d46add4d0"}, + {file = "python_box-7.2.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:6b59b1e2741c9ceecdf5a5bd9b90502c24650e609cd824d434fed3b6f302b7bb"}, + {file = "python_box-7.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23fae825d809ae7520fdeac88bb52be55a3b63992120a00e381783669edf589"}, + {file = "python_box-7.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:573b1abdcb7bd745fa404444f060ee62fc35a74f067181e55dcb43cfe92f2827"}, + {file = "python_box-7.2.0-py3-none-any.whl", hash = "sha256:a3c90832dd772cb0197fdb5bc06123b6e1b846899a1b53d9c39450d27a584829"}, + {file = "python_box-7.2.0.tar.gz", hash = "sha256:551af20bdab3a60a2a21e3435120453c4ca32f7393787c3a5036e1d9fc6a0ede"}, +] + +[package.extras] +all = ["msgpack", "ruamel.yaml (>=0.17)", "toml"] +msgpack = ["msgpack"] +pyyaml = ["PyYAML"] +ruamel-yaml = ["ruamel.yaml (>=0.17)"] +toml = ["toml"] +tomli = ["tomli", "tomli-w"] +yaml = ["ruamel.yaml (>=0.17)"] + [[package]] name = "pywin32-ctypes" version = "0.2.3" @@ -848,4 +883,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "862b5129b84b18fde1eb78996e25962d12a523d3132586807b493f6e3bb33cb2" +content-hash = "cc843697d836efc673aeb14dc07c77eea06f9cb566abb162b13ec96d36a44e27" diff --git a/pyproject.toml b/pyproject.toml index cfc7a3d..2589838 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ twine = "^5.1.1" pytest = "^8.3.3" ptpython = "^3.0.29" +python-box = "^7.2.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/tests/fixtures/bad.py b/tests/fixtures/bad.py index d57114f..f824992 100644 --- a/tests/fixtures/bad.py +++ b/tests/fixtures/bad.py @@ -1,6 +1,10 @@ +import logging from pathlib import Path from bad import behavior def main(): - pass + logger = logging.getLogger(__name__) + logger.info('I am also bad') + logging.info('I start with a captial letter, that is why I am bad') + logging.info('Another line starts with a capital, this is bad') diff --git a/tests/fixtures/good.py b/tests/fixtures/good.py index 4e226bb..e6678ce 100644 --- a/tests/fixtures/good.py +++ b/tests/fixtures/good.py @@ -1,3 +1,4 @@ +import logging import namespace.x.y from . import something from .. import something_else @@ -9,3 +10,9 @@ def f(): namespace.x.y.go() + logger = logging.getLogger(__name__) + logging.info('hi there') + logger.info('hello') + # logger.info('I start with a capital but I am commented out') + logging.info('I start with a capital, but I have a comment that allows this') # foxylint-loggingcase:ignore + logging.info('Another line starts with a capital, but I have a comment that allows this') # foxylint-loggingcase:ignore diff --git a/tests/test_blackbox.py b/tests/test_blackbox.py index e3e1ab6..bda56a4 100644 --- a/tests/test_blackbox.py +++ b/tests/test_blackbox.py @@ -1,15 +1,28 @@ +import pytest import pathlib import foxylint.imports +import foxylint.loggingcase +import box HERE = pathlib.Path(__file__).parent -def test_blackbox(): +@pytest.fixture +def files(): good = str(HERE / 'fixtures' / 'good.py') bad = str(HERE / 'fixtures' / 'bad.py') - files = [good, bad] + return box.Box(good=good, bad=bad) + + +def test_imports(files): LOGGING_PATTERN = 'from mylogging import logger' ACCEPTABLE_PATTERNS = [LOGGING_PATTERN] - findings = foxylint.imports.analyze(files, acceptable_patterns=ACCEPTABLE_PATTERNS) - assert findings[good]['ok'] is True - assert findings[bad]['ok'] is False + findings = foxylint.imports.analyze([files.good, files.bad], acceptable_patterns=ACCEPTABLE_PATTERNS) + assert findings[files.good]['ok'] is True + assert findings[files.bad]['ok'] is False + + +def test_loggingcase(files): + findings = foxylint.loggingcase.analyze([files.good, files.bad]) + assert findings[files.good]['ok'] is True + assert findings[files.bad]['ok'] is False