Skip to content

Mypy: static type checker for Python #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions cpplint.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
same line, but it is far from perfect (in either direction).
"""

from __future__ import annotations

import codecs
import collections
import copy
Expand All @@ -57,7 +59,7 @@
import xml.etree.ElementTree

# if empty, use defaults
_valid_extensions = set()
_valid_extensions: set[str] = set()

__VERSION__ = "2.0.1"

Expand Down Expand Up @@ -830,7 +832,7 @@
]

# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
_CHECK_REPLACEMENT = {macro_var: {} for macro_var in _CHECK_MACROS}
_CHECK_REPLACEMENT: dict[str, dict[str, str]] = {macro_var: {} for macro_var in _CHECK_MACROS}

for op, replacement in [
("==", "EQ"),
Expand Down Expand Up @@ -934,7 +936,7 @@

# {str, set(int)}: a map from error categories to sets of linenumbers
# on which those errors are expected and should be suppressed.
_error_suppressions = {}
_error_suppressions: dict[str, set[int]] = {}

# The root directory used for deriving header guard CPP variable.
# This is set by --root flag.
Expand Down Expand Up @@ -964,7 +966,7 @@

# Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc.
# This is set by --headers flag.
_hpp_headers = set()
_hpp_headers: set[str] = set()


class ErrorSuppressions:
Expand Down Expand Up @@ -1034,7 +1036,7 @@ def Clear(self):
self._open_block_suppression = None


_error_suppressions = ErrorSuppressions()
_error_suppressions = ErrorSuppressions() # type: ignore[assignment]


def ProcessHppHeadersOption(val):
Expand Down Expand Up @@ -6609,7 +6611,7 @@ def ExpectingFunctionArgs(clean_lines, linenum):
)


_HEADERS_CONTAINING_TEMPLATES = (
_HEADERS_CONTAINING_TEMPLATES: tuple[tuple[str, tuple[str, ...]], ...] = (
("<deque>", ("deque",)),
(
"<functional>",
Expand Down Expand Up @@ -6705,7 +6707,7 @@ def ExpectingFunctionArgs(clean_lines, linenum):
("<slist>", ("slist",)),
)

_HEADERS_MAYBE_TEMPLATES = (
_HEADERS_MAYBE_TEMPLATES: tuple[tuple[str, tuple[str, ...]], ...] = (
(
"<algorithm>",
(
Expand All @@ -6721,15 +6723,15 @@ def ExpectingFunctionArgs(clean_lines, linenum):
)

# Non templated types or global objects
_HEADERS_TYPES_OR_OBJS = (
_HEADERS_TYPES_OR_OBJS: tuple[tuple[str, tuple[str, ...]], ...] = (
# String and others are special -- it is a non-templatized type in STL.
("<string>", ("string",)),
("<iostream>", ("cin", "cout", "cerr", "clog", "wcin", "wcout", "wcerr", "wclog")),
("<cstdio>", ("FILE", "fpos_t")),
)

# Non templated functions
_HEADERS_FUNCTIONS = (
_HEADERS_FUNCTIONS: tuple[tuple[str, tuple[str, ...]], ...] = (
(
"<cstdio>",
(
Expand Down Expand Up @@ -6780,7 +6782,7 @@ def ExpectingFunctionArgs(clean_lines, linenum):
),
)

_re_pattern_headers_maybe_templates = []
_re_pattern_headers_maybe_templates: list[tuple[re.Pattern, str, str]] = []
for _header, _templates in _HEADERS_MAYBE_TEMPLATES:
# Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
# 'type::max()'.
Expand All @@ -6796,7 +6798,7 @@ def ExpectingFunctionArgs(clean_lines, linenum):
)

# Other scripts may reach in and modify this pattern.
_re_pattern_templates = []
_re_pattern_templates: list[tuple[re.Pattern, str, str]] = []
for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
_re_pattern_templates.extend(
(
Expand All @@ -6807,14 +6809,14 @@ def ExpectingFunctionArgs(clean_lines, linenum):
for _template in _templates
)

_re_pattern_types_or_objs = []
_re_pattern_types_or_objs: list[tuple[re.Pattern, object | type, str]] = []
for _header, _types_or_objs in _HEADERS_TYPES_OR_OBJS:
_re_pattern_types_or_objs.extend(
(re.compile(r"\b" + _type_or_obj + r"\b"), _type_or_obj, _header)
for _type_or_obj in _types_or_objs
)

_re_pattern_functions = []
_re_pattern_functions: list[tuple[re.Pattern, str, str]] = []
for _header, _functions in _HEADERS_FUNCTIONS:
# Match printf(..., ...), but not foo->printf, foo.printf or
# 'type::printf()'.
Expand Down
10 changes: 6 additions & 4 deletions cpplint_clitest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

"""Command Line interface integration test for cpplint.py."""

from __future__ import annotations

import contextlib
import glob
import os
Expand All @@ -39,23 +41,23 @@
import tempfile

import pytest
from parameterized import parameterized
from testfixtures import compare
from parameterized import parameterized # type: ignore[import-untyped]
from testfixtures import compare # type: ignore[import-untyped]

import cpplint # noqa: F401

BASE_CMD = sys.executable + " " + os.path.abspath("./cpplint.py ")


def run_shell_command(cmd: str, args: str, cwd="."):
def run_shell_command(cmd: str, args: str, cwd: str = ".") -> tuple[int, bytes, bytes]:
"""Executes a command

Args:
cmd: A string to execute.
args: A string with arguments to the command.
cwd: from which folder to run.
"""
cmd, args = cmd.split(), args.split()
cmd, args = cmd.split(), args.split() # type: ignore[assignment]
proc = subprocess.run(cmd + args, cwd=cwd, capture_output=True, check=False)
out, err = proc.stdout, proc.stderr

Expand Down
6 changes: 4 additions & 2 deletions cpplint_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

# TODO(unknown): Add a good test that tests UpdateIncludeState.

from __future__ import annotations

import codecs
import os
import platform
Expand All @@ -43,7 +45,7 @@
import tempfile

import pytest
from parameterized import parameterized
from parameterized import parameterized # type: ignore[import-untyped]

import cpplint

Expand All @@ -58,7 +60,7 @@ def codecs_latin_encode(x):
class ErrorCollector:
# These are a global list, covering all categories seen ever.
_ERROR_CATEGORIES = cpplint._ERROR_CATEGORIES
_SEEN_ERROR_CATEGORIES = {}
_SEEN_ERROR_CATEGORIES: dict[str, str] = {}

def __init__(self, assert_fn):
"""assert_fn: a function to call when we notice a problem."""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dynamic = [ "version" ]
dependencies = [ ]

optional-dependencies.dev = [
"mypy",
"parameterized",
"pylint>=2.11",
"pytest",
Expand Down
3 changes: 3 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
envlist = py38, py39, py3.10, py311, py312, py313, pypy3
skip_missing_interpreters = true


[testenv]
allowlist_externals = sh
extras = dev

commands =
{envpython} -m pytest {posargs:}
{envpython} -m pylint cpplint.py
sh -c 'mypy *.py'
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy