mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-05 03:26:53 +00:00
151 lines
4.3 KiB
Python
151 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from typing import Any
|
|
|
|
from coverage import CoveragePlugin
|
|
from coverage.config import CoverageConfig
|
|
from coverage.config import DEFAULT_EXCLUDE
|
|
from coverage.plugin_support import Plugins
|
|
|
|
_ALL = (
|
|
# os.name
|
|
'nt', 'posix',
|
|
# sys.platform
|
|
'cygwin', 'darwin', 'linux', 'msys', 'win32',
|
|
# sys.implementation.name
|
|
'cpython', 'pypy',
|
|
)
|
|
|
|
|
|
def _plat_impl_pragmas() -> list[str]:
|
|
tags = {os.name, sys.platform, sys.implementation.name}
|
|
ret = [fr'# pragma: {tag} cover\b' for tag in _ALL if tag not in tags]
|
|
ret.extend(fr'# pragma: {tag} no cover\b' for tag in tags)
|
|
return ret
|
|
|
|
|
|
def _lt(n: int) -> str:
|
|
n_s = str(n)
|
|
digit = r'\d'
|
|
|
|
parts = [
|
|
f'{n_s[:i]}[0-{int(n_s[i]) - 1}]{len(n_s[i + 1:]) * digit}'
|
|
for i in range(len(n_s))
|
|
if n_s[i] != '0'
|
|
]
|
|
if len(n_s) > 1:
|
|
parts.append(f'{digit}{{1,{len(n_s) - 1}}}')
|
|
|
|
return f'({"|".join(parts)})'
|
|
|
|
|
|
def _gt(n: int) -> str:
|
|
n_s = str(n)
|
|
digit = r'\d'
|
|
|
|
parts = [
|
|
f'{n_s[:i]}[{int(n_s[i]) + 1}-9]{len(n_s[i + 1:]) * digit}'
|
|
for i in range(len(n_s))
|
|
if n_s[i] != '9'
|
|
]
|
|
parts.append(f'{digit}{{{len(n_s) + 1},}}')
|
|
|
|
return f'({"|".join(parts)})'
|
|
|
|
|
|
def _version_pragmas(
|
|
major: int = sys.version_info[0],
|
|
minor: int = sys.version_info[1],
|
|
) -> list[str]:
|
|
return [
|
|
# <
|
|
fr'# pragma: <=?{_lt(major)}\.\d+ cover\b',
|
|
fr'# pragma: <=?{major}\.{_lt(minor)} cover\b',
|
|
fr'# pragma: <{major}\.{minor} cover\b',
|
|
# >
|
|
fr'# pragma: >=?{_gt(major)}\.\d+ cover\b',
|
|
fr'# pragma: >=?{major}\.{_gt(minor)} cover\b',
|
|
fr'# pragma: >{major}\.{minor} cover\b',
|
|
# != / ==
|
|
fr'# pragma: !={major}\.{minor} cover\b',
|
|
fr'# pragma: ==(?!{major}\.{minor})\d+\.\d+ cover\b',
|
|
]
|
|
|
|
|
|
OPTIONS: tuple[tuple[str, Any], ...] = (
|
|
('run:branch', True),
|
|
|
|
('report:show_missing', True),
|
|
('report:skip_covered', True),
|
|
)
|
|
EXTEND = (
|
|
('run:omit', ['*/__main__.py', '*/setup.py']),
|
|
(
|
|
'report:exclude_lines',
|
|
[
|
|
# a more strict default pragma
|
|
r'# pragma: no cover\b',
|
|
# allow defensive code
|
|
r'^\s*raise AssertionError\b',
|
|
r'^\s*raise NotImplementedError\b',
|
|
r'^\s*return NotImplemented\b',
|
|
r'^\s*raise$',
|
|
# typing-related code
|
|
r'^\s*if (False|TYPE_CHECKING):',
|
|
r': \.\.\.(\s*#.*)?$',
|
|
r'^ +\.\.\.$',
|
|
r'-> [\'"]?NoReturn[\'"]?:',
|
|
r'^\s*assert_never\b',
|
|
# non-runnable code
|
|
r'^if __name__ == [\'"]__main__[\'"]:$',
|
|
*_plat_impl_pragmas(),
|
|
*_version_pragmas(),
|
|
],
|
|
),
|
|
(
|
|
'report:partial_branches',
|
|
[
|
|
r'# pragma: no branch\b',
|
|
# platform specific no cover
|
|
fr'# pragma: ({"|".join(_ALL)}) (no )?cover\b',
|
|
# version specific no cover
|
|
r'# pragma: (>=?|<=?|==|!=)\d+\.\d+ cover\b',
|
|
],
|
|
),
|
|
)
|
|
|
|
|
|
class CovDefaults(CoveragePlugin):
|
|
def __init__(self, subtract_omit: str = '') -> None:
|
|
self._subtract_omit = subtract_omit.split()
|
|
|
|
def configure(self, config: CoverageConfig) -> None:
|
|
for k, v in OPTIONS:
|
|
config.set_option(k, v)
|
|
if config.get_option('run:source') is None:
|
|
config.set_option('run:source', ['.'])
|
|
for k, v in EXTEND:
|
|
before = set(config.get_option(k) or ())
|
|
before.update(v)
|
|
config.set_option(k, sorted(before))
|
|
|
|
# subtract omit settings if requested
|
|
if self._subtract_omit:
|
|
omit = set(config.get_option('run:omit'))
|
|
omit.difference_update(self._subtract_omit)
|
|
config.set_option('run:omit', sorted(omit))
|
|
|
|
# remove DEFAULT_EXCLUDE, we add a more-strict casing
|
|
exclude = set(config.get_option('report:exclude_lines'))
|
|
exclude.difference_update(DEFAULT_EXCLUDE)
|
|
config.set_option('report:exclude_lines', sorted(exclude))
|
|
|
|
# fail_under: if they specify a value then honor it
|
|
if not config.get_option('report:fail_under'):
|
|
config.set_option('report:fail_under', 100)
|
|
|
|
|
|
def coverage_init(reg: Plugins, options: dict[str, str]) -> None:
|
|
reg.add_configurer(CovDefaults(**options))
|