From f389cadf56b941353e6a2d6a670d6bff5ff1019d Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 23:15:08 +0100 Subject: [PATCH 1/9] Add a no-op check job to GHA for branch protection This patch adds an "empty" job that depends on all the important ones making it possible to use just this `check` job in the branch protection settings. This reduces the maintenance burden by preventing the need to update these settings on any changes to the job declarations. --- .github/workflows/test-library.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/test-library.yml b/.github/workflows/test-library.yml index f35d21019c..1d97322d56 100644 --- a/.github/workflows/test-library.yml +++ b/.github/workflows/test-library.yml @@ -116,3 +116,16 @@ jobs: --parallel auto --parallel-live --skip-missing-interpreters false + + check: # This job does nothing and is only used for the branch protection + needs: + - build + - tox + + runs-on: ubuntu-latest + + steps: + - name: Report success of the test matrix + run: >- + print("All's good") + shell: python From 3194f152c63574f8f825de441e4466345caf76d3 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 23:17:23 +0100 Subject: [PATCH 2/9] Add a config for YAMLLint --- .yamllint | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .yamllint diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000000..3b3a84c8b2 --- /dev/null +++ b/.yamllint @@ -0,0 +1,8 @@ +--- +extends: default + +rules: + indentation: + level: error + indent-sequences: false +... From b6104ea2dba87059bbe6f73b01322688baa6eb3b Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 23:17:39 +0100 Subject: [PATCH 3/9] Add a config for flake8 --- .flake8 | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000000..cf84c8257f --- /dev/null +++ b/.flake8 @@ -0,0 +1,236 @@ +[flake8] + +# Don't even try to analyze these: +extend-exclude = + # No need to traverse egg info dir + *.egg-info, + # GitHub configs + .github, + # Cache files of MyPy + .mypy_cache, + # Cache files of pytest + .pytest_cache, + # Temp dir of pytest-testmon + .tmontmp, + # Occasional virtualenv dir + .venv, + # VS Code + .vscode, + # Temporary build dir + build, + # This contains sdists and wheels of proxy.py that we don't want to check + dist, + # Occasional virtualenv dir + env, + # Metadata of `pip wheel` cmd is autogenerated + pip-wheel-metadata, + +# IMPORTANT: avoid using ignore option, always use extend-ignore instead +# Completely and unconditionally ignore the following errors: +extend-ignore = + I # flake8-isort is drunk + we have isort integrated into pre-commit + B009 # FIXME: `getattr()` called with a constant arg + C812 # FIXME: missing trailing comma + C819 # FIXME: inline trailing comma + D101 + D102 + D103 + D105 + D106 + D107 + D203 + D205 + D208 + D209 + D212 + D213 + D300 + D400 + D401 + D402 + D403 + D404 + D405 + D407 + D412 + D413 + D415 + DAR101 # FIXME: undocumented docstring param + DAR201 # FIXME: no "returns" in docstring + DAR301 # FIXME: no "yields" in docstring + DAR401 # FIXME: no "raises" in docstring + E800 # FIXME: commented out code + N400 # FIXME: escaping with backslash at EOL + N801 # FIXME: class name should use ProudCamelCase + N802 # FIXME: func name should be lowercase + N816 # FIXME: mixed case var name + P101 # FIXME: format string with unindexed params + PT009 # FIXME: pytest encourages use of `assert` + PT018 # FIXME: use multiple `assert`s instead of one complex + Q000 # FIXME: inconsistent double quotes use when single ones are needed + Q001 # FIXME: use double quotes in multiline strings + Q002 # FIXME: use double quote docstrings + Q003 # FIXME: avoid escaping in-string quotes + RST201 # FIXME: missing trailing blank line in docstring + RST203 # FIXME: no trailing blank line in docstring + RST301 # FIXME: unexpected indent in docstring + S101 # FIXME: assertions are thrown away in optimized mode, needs audit + S104 # FIXME: bind-all interface listen + S105 # FIXME: hardcoded password? + S303 # FIXME: insecure hash func + S311 # FIXME: `random` needs auditing + S404 # FIXME: `subprocess` use needs auditing + S603 # FIXME: audit untrusted `subprocess.Popen` input + S607 # FIXME: running subprocess with a non-absolute executable path + WPS100 # FIXME: unhelpful module name + WPS102 # FIXME: incorrect module name pattern + WPS110 # FIXME: unhelpful var name + WPS111 # FIXME: too short var name + WPS114 # FIXME: underscored numbers in var name + WPS115 # FIXME: uppercase class attr + WPS118 # FIXME: long func name + WPS120 # FIXME: regular name w/ trailing underscore + WPS121 # FIXME: unused var used 0_O + WPS122 # FIXME: unused var definition 0_O + WPS201 # FIXME: too many imports + WPS202 # FIXME: too many mod members + WPS203 # FIXME: too many mod imported names + WPS204 # FIXME: too much copy-paste + WPS210 # FIXME: too many local vars + WPS211 # FIXME: too many "__init__()" args + WPS212 # FIXME: too many "return"s + WPS213 # FIXME: too many expressions + WPS214 # FIXME: too many methods + WPS216 # FIXME: too many decorators + WPS219 # FIXME: deep object access is unreadable + WPS220 # FIXME: deep code nesting + WPS221 # FIXME: too big inline complexity / tested instructions + WPS222 # FIXME: too much logic in condition + WPS223 # FIXME: the code is too branchy + WPS225 # FIXME: too many "except"s + WPS226 # FIXME: magic string constant used too much, put it in a var + WPS229 # FIXME: try/except should wrap exactly one instruction + WPS230 # FIXME: too many public instance attrs + WPS231 # FIXME: insane complexity/code nesting in a function + WPS232 # FIXME: module is too complex + WPS234 # FIXME: annotation is too complex + WPS235 # FIXME: too many imported names from a single module + WPS237 # FIXME: too complex f-string + WPS300 # local folder imports are needed + WPS301 # FIXME: dotted import + WPS305 # this project is Python 3 only and so f-strings are allowed + WPS306 # this project is Python 3 so it doesn't need an explicit class base + WPS313 # FIXME: parens after keyword + WPS317 # enforces weird indents + WPS318 # enforces weird indents + WPS319 # FIXME: asymmetric closing bracket + WPS320 # FIXME: multiline func type annotation + WPS322 # FIXME: inline multiline str + WPS323 # false-positive: %-formatting in logging + WPS324 # FIXME: inconsistent "return" in func + WPS326 # doesn't allow implicit string concat + WPS328 # FIXME: useless `while` node + WPS336 # FIXME: explicit string concat + WPS337 # FIXME: multiline conditions + WPS338 # FIXME: unordered class methods + WPS339 # FIXME: meaningless leading zeros in number + WPS349 # FIXME: redundant slice + WPS360 # FIXME: unnecessary r-string + WPS361 # FIXME: inconsistent comprehension structure + WPS403 # FIXME: `# noqa` overuse + WPS407 # FIXME: mutable mod const + WPS408 # FIXME: duplicate logical condition + WPS410 # allow `__all__` + WPS412 # FIXME: logic in `__init__` + WPS414 # FIXME: consusing unpacking target + WPS420 # FIXME: pointless keyword like `pass` + WPS421 # FIXME: call to `print()` + WPS425 # FIXME: bool non-keyword arg + WPS427 # FIXME: unreachable code + WPS428 # FIXME: pointless statement + WPS430 # FIXME: nested func + WPS431 # FIXME: nested class + WPS432 # FIXME: magic number w/o assigned context/name + WPS433 # FIXME: nested import + WPS437 # FIXME: protected attr access + WPS440 # FIXME: block vars overlap + WPS441 # FIXME: control var use after block + WPS442 # FIXME: outer scope var shadowing + WPS453 # FIXME: executable file w/o shebang + WPS454 # FIXME: don't raise a broad exception, use a specific one + WPS457 # FIXME: infinite `while` + WPS458 # FIXME: import collision + WPS460 # FIXME: single element unpacking + WPS464 # FIXME: empty comment + WPS501 # FIXME: "finally" in "try" w/o "except" + WPS504 # FIXME: invert a negated condition + WPS505 # FIXME: nested "try" in "try" + WPS507 # FIXME: useless `len()` + WPS508 # FIXME: misused `not` in if-clause + WPS509 # FIXME: incorrect ternary nesting + WPS510 # FIXME: if-clause with `in` operator w/ wrong set semantics + WPS513 # FIXME: implicit `elif` + WPS515 # FIXME: implicit `open()` w/o a CM + WPS518 # FIXME: implicit `enumerate()` pattern + WPS519 # FIXME: implicit `sum()` pattern + WPS528 # FIXME: implicit `dict.items()` pattern + WPS529 # FIXME: implicit `dict.get()` pattern + WPS531 # FIXME: simplifiable returning `if` in func + WPS602 # FIXME: `@staticmethod` is usually a code smell, use module funcs + WPS604 # FIXME: incorrect class body node + WPS605 # FIXME: method w/o args + WPS609 # FIXME: direct call to magic method + WPS612 # FIXME: useless `__init__()` override + WPS613 # FIXME: unmatching super method access + WPS615 # FIXME: unpythonic setter/getter + +# https://wemake-python-stylegui.de/en/latest/pages/usage/formatter.html +format = wemake + +# Let's not overcomplicate the code: +#max-complexity = 10 +# FIXME: this is a lot! +max-complexity = 19 + +# Accessibility/large fonts and PEP8 friendly: +#max-line-length = 79 +# Accessibility/large fonts and PEP8 unfriendly: +#max-line-length = 100 +# Even more Accessibility/large fonts and PEP8 unfriendlier: +max-line-length = 127 + +# Allow certain violations in certain files: +per-file-ignores = + + # E800 reports a lot of false-positives for legit + # tool-related comments; + # WPS412 logic of an extension is in __init__.py file; + # FIXME: WPS201 too many imports + # FIXME: WPS402 too many `noqa`s + #proxy/__init__.py: E800, WPS201, WPS402, WPS412 + + # There are multiple `assert`s (S101) + # and subprocesses (import – S404; call – S603) in tests; + # also, using fixtures looks like shadowing the outer scope (WPS442); + # and finally it's impossible to have <= members in tests (WPS202): + tests/**.py: S101, S404, S603, WPS202, WPS442 + +# wemake-python-styleguide +show-source = true + +# flake8-pytest-style +# PT001: +pytest-fixture-no-parentheses = true +# PT006: +pytest-parametrize-names-type = tuple +# PT007: +pytest-parametrize-values-type = tuple +pytest-parametrize-values-row-type = tuple + +# flake8-rst-docstrings +rst-roles = + # Built-in Sphinx roles: + py:class, + py:meth, + # Sphinx's internal role: + event, From 6f3ba33a6bf7faafbab5d630d7a92066a51a7473 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 22:51:49 +0100 Subject: [PATCH 4/9] Add an initial auto-generated PyLint config --- .pylintrc | 560 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 560 insertions(+) create mode 100644 .pylintrc diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000000..862acdf47c --- /dev/null +++ b/.pylintrc @@ -0,0 +1,560 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-allow-list= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) +extension-pkg-whitelist= + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= + +# Specify a score threshold to be exceeded before program exits with error. +fail-under=10.0 + +# Files or directories to be skipped. They should be base names, not paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the ignore-list. The +# regex matches against paths. +ignore-paths= + +# Files or directories matching the regex patterns are skipped. The regex +# matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Min Python version to use for version dependend checks. Will default to the +# version used to run pylint. +py-version=3.9 + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + use-symbolic-message-instead + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'error', 'warning', 'refactor', and 'convention' +# which contain the number of messages in each category, as well as 'statement' +# which is the total number of statements analyzed. This score is used by the +# global evaluation report (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +#class-attribute-rgx= + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. +#class-const-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +#variable-rgx= + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[LOGGING] + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + +# Regular expression of note tags to take in consideration. +#notes-rgx= + + +[SIMILARITIES] + +# Comments are removed from the similarity computation +ignore-comments=yes + +# Docstrings are removed from the similarity computation +ignore-docstrings=yes + +# Imports are removed from the similarity computation +ignore-imports=no + +# Signatures are removed from the similarity computation +ignore-signatures=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it work, +# install the 'python-enchant' package. +spelling-dict= + +# List of comma separated words that should be considered directives if they +# appear and the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. +check-str-concat-over-line-jumps=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of names allowed to shadow builtins +allowed-redefined-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[CLASSES] + +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[DESIGN] + +# List of qualified class names to ignore when counting class parents (see +# R0901) +ignored-parents= + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules= + +# Output a graph (.gv or any supported image format) of external dependencies +# to the given file (report RP0402 must not be disabled). +ext-import-graph= + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be +# disabled). +import-graph= + +# Output a graph (.gv or any supported image format) of internal dependencies +# to the given file (report RP0402 must not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "BaseException, Exception". +overgeneral-exceptions=BaseException, + Exception From d6024765f1d613c28be3e8a1784bf89e1bb6f381 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 22:52:13 +0100 Subject: [PATCH 5/9] Align pylint line length settings in with flake8 --- .pylintrc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 862acdf47c..4db8703375 100644 --- a/.pylintrc +++ b/.pylintrc @@ -271,7 +271,10 @@ indent-after-paren=4 indent-string=' ' # Maximum number of characters on a single line. -max-line-length=100 +# Accessibility/large fonts and PEP8 friendly: +#max-line-length = 79 +# Accessibility/large fonts and PEP8 unfriendly: +max-line-length = 127 # Maximum number of lines in a module. max-module-lines=1000 From 04dbdb8f5ff634e38750dde42efac8d10fe00c00 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 22:54:05 +0100 Subject: [PATCH 6/9] Colorize the pylint report output --- .pylintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 4db8703375..03b6f3772a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -110,7 +110,8 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. -output-format=text +#output-format=text +output-format=colorized # Tells whether to display a full report or only the messages. reports=no From aacbd19b52a551418a3e36ae24e68310afe190d7 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 23:14:14 +0100 Subject: [PATCH 7/9] Correct spelling mistakes caught by `codespell` --- README.md | 2 +- proxy/core/base/tcp_server.py | 2 +- proxy/http/proxy/server.py | 2 +- tests/integration/main.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 918be3c82f..13869df96b 100644 --- a/README.md +++ b/README.md @@ -1193,7 +1193,7 @@ if __name__ == '__main__': Note that it supports: 1. The fully-qualified name of a class as `bytes` -2. Any `type` instance for a Proxy.py plugin class. This is espacially useful for custom plugins defined locally. +2. Any `type` instance for a Proxy.py plugin class. This is especially useful for custom plugins defined locally. # Unit testing with proxy.py diff --git a/proxy/core/base/tcp_server.py b/proxy/core/base/tcp_server.py index bff043113b..d4f516836e 100644 --- a/proxy/core/base/tcp_server.py +++ b/proxy/core/base/tcp_server.py @@ -30,7 +30,7 @@ class BaseTcpServerHandler(Work): Implementations must provide: a) handle_data(data: memoryview) - c) (optionally) intialize, is_inactive and shutdown methods + c) (optionally) initialize, is_inactive and shutdown methods """ def __init__(self, *args: Any, **kwargs: Any) -> None: diff --git a/proxy/http/proxy/server.py b/proxy/http/proxy/server.py index 5b26b17163..9bd3465290 100644 --- a/proxy/http/proxy/server.py +++ b/proxy/http/proxy/server.py @@ -342,7 +342,7 @@ def on_client_data(self, raw: memoryview) -> Optional[memoryview]: # For scenarios when an upstream connection was never established, # let plugin do whatever they wish to. These are special scenarios # where plugins are trying to do something magical. Within the core - # we don't know the context. Infact, we are not even sure if data + # we don't know the context. In fact, we are not even sure if data # exchanged is http spec compliant. # # Hence, here we pass raw data to HTTP proxy plugins as is. diff --git a/tests/integration/main.sh b/tests/integration/main.sh index d75d9781de..87f37570e2 100755 --- a/tests/integration/main.sh +++ b/tests/integration/main.sh @@ -1,7 +1,7 @@ #!/bin/bash # TODO: Option to also shutdown proxy.py after -# integration testing is done. Atleast on +# integration testing is done. At least on # macOS and ubuntu, pkill and kill commands # will do the job. # From b9ca478444c22ddc65d7c955789c48e0726b5840 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 23:12:00 +0100 Subject: [PATCH 8/9] Disable all currently violated PyLint rules --- .pylintrc | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 03b6f3772a..8ed0ab46d7 100644 --- a/.pylintrc +++ b/.pylintrc @@ -85,7 +85,52 @@ disable=raw-checker-failed, suppressed-message, useless-suppression, deprecated-pragma, - use-symbolic-message-instead + use-symbolic-message-instead, + # FIXME: Everything below has been violated at the time of the + # FIXME: initial addition. All of these rules must be fixed and + # FIXME: removed/re-enabled over time. + arguments-differ, + attribute-defined-outside-init, + broad-except, + consider-using-dict-items, + consider-using-enumerate, + consider-using-f-string, + consider-using-ternary, + consider-using-with, + cyclic-import, + deprecated-method, + duplicate-code, + fixme, + global-variable-not-assigned, + invalid-name, + logging-format-interpolation, + logging-not-lazy, + missing-class-docstring, + missing-function-docstring, + no-else-raise, + no-self-use, + no-value-for-parameter, + protected-access, + raise-missing-from, + raising-format-tuple, + redefined-outer-name, + super-init-not-called, + superfluous-parens, + too-few-public-methods, + too-many-arguments, + too-many-branches, + too-many-instance-attributes, + too-many-locals, + too-many-nested-blocks, + too-many-public-methods, + too-many-return-statements, + too-many-statements, + unnecessary-pass, + unreachable, + unused-argument, + useless-return, + useless-super-delegation, + wrong-import-order, # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option From d8c507dbafb645f744c8ffce30fea9181316a303 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 2 Nov 2021 23:18:13 +0100 Subject: [PATCH 9/9] Start managing the linters setup with pre-commit --- .github/workflows/test-library.yml | 5 +- .pre-commit-config.yaml | 203 +++++++++++++++++++++++++++++ Makefile | 3 +- tox.ini | 26 ++++ 4 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/test-library.yml b/.github/workflows/test-library.yml index 1d97322d56..433529d95b 100644 --- a/.github/workflows/test-library.yml +++ b/.github/workflows/test-library.yml @@ -24,10 +24,6 @@ jobs: pip install -r requirements.txt pip install -r requirements-testing.txt pip install -r requirements-tunnel.txt - - name: Quality Check - run: | - flake8 --ignore=W504 --max-line-length=127 --max-complexity=19 proxy/ tests/ - mypy --strict --ignore-missing-imports proxy/ tests/ - name: Run Tests run: pytest --cov=proxy tests/ - name: Upload coverage to Codecov @@ -49,6 +45,7 @@ jobs: matrix: toxenv: - cleanup-dists,build-dists,metadata-validation + - lint fail-fast: false env: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..f6c2de3370 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,203 @@ +--- +repos: +# - repo: https://github.com/asottile/add-trailing-comma.git +# rev: v2.0.1 +# hooks: +# - id: add-trailing-comma + +# - repo: https://github.com/timothycrosley/isort.git +# rev: 5.4.2 +# hooks: +# - id: isort +# args: +# - --honor-noqa + +- repo: https://github.com/Lucas-C/pre-commit-hooks.git + rev: v1.1.7 + hooks: + - id: remove-tabs + exclude: | + (?x) + ^ + helper/proxy\.pac| + Makefile| + proxy/common/pki\.py| + README\.md| + .+\.(plist|pbxproj) + $ + +- repo: https://github.com/pre-commit/pre-commit-hooks.git + rev: v4.0.1 + hooks: + # Side-effects: + - id: trailing-whitespace + exclude: | + (?x) + ^ + \.github/workflows/codeql-analysis\.yml| + dashboard/src/core/plugins/inspect_traffic\.json + $ + - id: check-merge-conflict + - id: double-quote-string-fixer + exclude: | + (?x) + ^ + ( + tests/( + http/exceptions/test_http_proxy_auth_failed| + plugin/test_http_proxy_plugins + )| + proxy/( + common/constants| + plugin/(cache/store/disk|filter_by_url_regex|proxy_pool) + ) + )\.py + $ + - id: end-of-file-fixer + exclude: | + (?x) + ^ + dashboard/( + src/core/plugins/inspect_traffic\.json| + static/bootstrap-4\.3\.1\.min\.(cs|j)s + )| + menubar/proxy\.py/( + Assets\.xcassets/( + AppIcon\.appiconset/| + StatusBarButtonImage\.imageset/| + )| + Preview\sContent/Preview\sAssets\.xcassets/ + )Contents\.json| + requirements-release\.txt + $ + - id: requirements-txt-fixer + exclude: >- + ^requirements(|-(release|testing|tunnel))\.txt$ + # Non-modifying checks: + - id: name-tests-test + args: + - --django + exclude: >- + ^tests/plugin/utils\.py$ + files: >- + ^tests/[^_].*\.py$ + - id: check-added-large-files + - id: check-byte-order-marker + - id: check-case-conflict + # disabled due to pre-commit/pre-commit-hooks#159 + #- id: check-docstring-first + - id: check-json + - id: check-symlinks + - id: check-yaml + # args: + # - --unsafe + - id: detect-private-key + + # Heavy checks: + - id: check-ast + - id: debug-statements + +- repo: https://github.com/PyCQA/pydocstyle.git + rev: 6.1.1 + hooks: + - id: pydocstyle + additional_dependencies: + - toml + args: + - |- + --ignore= + D101, + D102, + D103, + D105, + D106, + D107, + D203, + D205, + D208, + D209, + D212, + D213, + D300, + D400, + D401, + D402, + D403, + D404, + D405, + D407, + D412, + D413, + D415, + +- repo: https://github.com/codespell-project/codespell + rev: v2.1.0 + hooks: + - id: codespell + exclude: >- + ^.+\.min\.js$ + +- repo: https://github.com/adrienverge/yamllint.git + rev: v1.26.2 + hooks: + - id: yamllint + exclude: | + (?x) + ^ + \.pre-commit-config\.yaml| + ( + \.github/( + workflows/( + codeql-analysis|test-(brew|dashboard|docker|library) + )| + FUNDING + )| + codecov + )\.yml + $ + args: + - --strict + types: [file, yaml] + +- repo: https://github.com/PyCQA/flake8.git + rev: 3.9.2 + hooks: + - id: flake8 + language_version: python3 + additional_dependencies: + - flake8-2020 >= 1.6.0 + - flake8-docstrings >= 1.5.0 + - flake8-pytest-style >= 1.2.2 + - wemake-python-styleguide ~= 0.15.0 + +- repo: https://github.com/pre-commit/mirrors-mypy.git + rev: v0.910 + hooks: + - id: mypy + args: + # FIXME: get rid of missing imports ignore + - --ignore-missing-imports + - --install-types + - --namespace-packages + - --non-interactive + - --pretty + - --show-column-numbers + - --show-error-codes + - --show-error-context + - --strict + - --strict-optional + - examples/ + - proxy/ + - tests/ + pass_filenames: false + +- repo: local + hooks: + - id: pylint + language: system + name: PyLint + files: \.py$ + entry: python -m pylint + args: [] + stages: + - manual diff --git a/Makefile b/Makefile index f165b9a288..ea356d8671 100644 --- a/Makefile +++ b/Makefile @@ -89,8 +89,7 @@ lib-clean: rm -rf .hypothesis lib-lint: - flake8 --ignore=W504 --max-line-length=127 --max-complexity=19 examples/ proxy/ tests/ - mypy --strict --ignore-missing-imports examples/ proxy/ tests/ + python -m tox -e lint lib-test: lib-clean lib-version lib-lint pytest -v tests/ diff --git a/tox.ini b/tox.ini index 891000542b..c00908711b 100644 --- a/tox.ini +++ b/tox.ini @@ -67,3 +67,29 @@ commands = {envpython} -m twine check \ --strict \ {env:PEP517_OUT_DIR}{/}* + + +[testenv:lint] +description = + Enforce quality standards under `{basepython}` ({envpython}) +commands = + {envpython} -m \ + pre_commit run \ + --show-diff-on-failure \ + --hook-stage manual \ + {posargs:--all-files} + + # Print out the advice on how to install pre-commit from this env into Git: + -{envpython} -c \ + 'cmd = "{envpython} -m pre_commit install"; \ + scr_width = len(cmd) + 10; \ + sep = "=" * scr_width; \ + cmd_str = " $ \{cmd\}";' \ + 'print(f"\n\{sep\}\nTo install pre-commit hooks into the Git repo, run:\n\n\{cmd_str\}\n\n\{sep\}\n")' +deps = + pre-commit + pylint >= 2.5.3 + pylint-pytest < 1.1.0 + -r requirements-tunnel.txt +isolated_build = true +skip_install = true