diff --git a/git_hooks/pre-push b/git_hooks/pre-push index 5595417..76c9051 100755 --- a/git_hooks/pre-push +++ b/git_hooks/pre-push @@ -6,4 +6,4 @@ vagrant ssh -c ". activate \ && echo 'Checking mypy type annotations...' && mypy . \ && echo 'Checking if Black would reformat any code...' && black --check . \ && echo -n 'Running tests: ' && pytest -q \ - && echo 'Checking code style fully (takes a while)...' && pylama" + && echo 'Checking code style fully (takes a while)...' && prospector -M" diff --git a/tildes/prospector.yaml b/tildes/prospector.yaml new file mode 100644 index 0000000..d3f075d --- /dev/null +++ b/tildes/prospector.yaml @@ -0,0 +1,34 @@ +strictness: none +doc-warnings: true +max-line-length: 88 + +ignore-paths: + - alembic + +pep8: + disable: + # "multiple statements on one line" - type declarations seem to trigger sometimes + - E704 + +pep257: + disable: + # checks for blank lines after a function docstring, but Black will add one + # when the first code in the function is another function definition. + - D202 + - D203 # blank line before class docstring + - D213 # blank line after summary line for multi-line docstring + +pyflakes: + disable: + - F401 # unused imports, triggers in __init__.py and pylint can handle it otherwise + +pylint: + enable: all + disable: + - bad-continuation # let Black handle line-wrapping + - comparison-with-callable # seems to have a lot of false positives + - logging-fstring-interpolation # rather use f-strings than worry about this + - no-else-return # elif after return - could refactor to enable this check + - no-self-use # schemas do this a lot, would be nice to only disable for schemas + - too-few-public-methods # plenty of classes that don't need multiple methods + - too-many-instance-attributes # models have many instance attributes diff --git a/tildes/pylama.ini b/tildes/pylama.ini deleted file mode 100644 index 866ed4f..0000000 --- a/tildes/pylama.ini +++ /dev/null @@ -1,69 +0,0 @@ -[pylama] -linters = mccabe,pycodestyle,pydocstyle,pyflakes,pylint -skip = alembic/* - -# ignored checks: -# - D202 - pydocstyle check for blank lines after a function docstring, but -# Black will add one when the first code in the function is another -# function definition. -# - D203 - pydocstyle has two mutually exclusive checks (D203/D211) -# for whether a class docstring should have a blank line before -# it or not. I don't want a blank line, so D203 is disabled. -# - D213 - another pair of mutually exclusive pydocstyle checks, this -# time for whether a multi-line docstring's summary line should be -# on the first or second line. I want it to be on the first line, -# so D213 needs to be disabled. -# - E203 - checks for whitespace around : in slices, but Black adds it -# in some cases. -ignore = D202,D203,D213,E203 - -[pylama:pycodestyle] -max_line_length = 88 - -[pylama:pylint] -enable = all - -# disabled pylint checks: -# - bad-continuation (Black will handle wrapping lines properly) -# - missing-docstring (already reported by pydocstyle) -# - too-few-public-methods (more annoying than helpful, especially early on) -# - too-many-instance-attributes (overly-picky when models need many) -# - locally-disabled (don't need a warning about things I disable) -# - locally-enabled (or when checks are (re-)enabled) -# - suppressed-message (...a different message when I disable one?) -disable = - bad-continuation, - missing-docstring, - too-few-public-methods, - too-many-instance-attributes, - locally-disabled, - locally-enabled, - suppressed-message - -# The APIv0 and venusian.AttachInfo classes need to be ignored because pylint -# can't recognize dynamically-added methods/attrs, so all of the functions in -# cornice.Service like .get(), .post(), etc. cause errors. -ignored-classes = APIv0, venusian.AttachInfo - -[pylama:tildes/schemas/*] -# ignored checks for schemas specifically: -# - R0201 - method could be a function (for @pre_load-type methods) -ignore = R0201 - -[pylama:tildes/views/api/web/*] -# ignored checks for web API specifically: -# - C0103 - invalid function names (endpoints can have very long ones) -ignore = C0103 - -[pylama:tests/*] -# ignored checks for tests specifically: -# - D100 - missing module-level docstrings -# - C0103 - invalid function names (tests often have very long ones) -# - W0212 - access to protected member (useful/necessary for tests sometimes) -# - W0621 - redefining name from outer scope (that's how pytest fixtures work) -# - E1101 - has no member (mocks add members this can't detect) -ignore = D100,C0103,W0212,W0621,E1101 - -[pylama:*/__init__.py] -# ignore "imported but unused" inside __init__.py files -ignore = W0611 diff --git a/tildes/requirements-to-freeze.txt b/tildes/requirements-to-freeze.txt index 5e15100..58d0f38 100644 --- a/tildes/requirements-to-freeze.txt +++ b/tildes/requirements-to-freeze.txt @@ -2,7 +2,6 @@ ago alembic amqpy argon2_cffi -astroid==1.5.3 # pylama has issues with pylint 1.8.1 black bleach click @@ -15,12 +14,9 @@ mypy mypy-extensions Pillow prometheus-client +prospector psycopg2 publicsuffix2 -pydocstyle -pylama -pylama-pylint -pylint==1.7.5 # pylama has issues with 1.8.1 pyotp pyramid pyramid-debugtoolbar diff --git a/tildes/requirements.txt b/tildes/requirements.txt index 6c3cf2c..6bb3843 100644 --- a/tildes/requirements.txt +++ b/tildes/requirements.txt @@ -3,7 +3,7 @@ alembic==1.0.0 amqpy==0.13.1 appdirs==1.4.3 argon2-cffi==18.3.0 -astroid==1.5.3 +astroid==2.0.4 atomicwrites==1.2.0 attrs==18.1.0 backcall==0.1.0 @@ -16,6 +16,9 @@ chardet==3.0.4 click==6.7 cornice==3.4.0 decorator==4.3.0 +dodgy==0.1.9 +flake8==3.5.0 +flake8-polyfill==1.0.2 freezegun==0.3.10 gunicorn==19.9.0 html5lib==1.0.1 @@ -36,6 +39,7 @@ mypy==0.620 mypy-extensions==0.4.1 parso==0.3.1 PasteDeploy==1.5.2 +pep8-naming==0.7.0 pexpect==4.6.0 pickleshare==0.7.4 Pillow==5.2.0 @@ -44,18 +48,18 @@ plaster-pastedeploy==0.6 pluggy==0.7.1 prometheus-client==0.3.1 prompt-toolkit==1.0.15 +prospector==1.1.2 psycopg2==2.7.5 ptyprocess==0.6.0 publicsuffix2==2.20160818 py==1.6.0 -pycodestyle==2.4.0 +pycodestyle==2.3.1 pycparser==2.18 pydocstyle==2.1.1 -pyflakes==2.0.0 +pyflakes==1.6.0 Pygments==2.2.0 -pylama==7.4.3 -pylama-pylint==3.0.1 -pylint==1.7.5 +pylint==2.1.1 +pylint-plugin-utils==0.4 pyotp==2.2.6 pyramid==1.9.2 pyramid-debugtoolbar==4.4 @@ -74,6 +78,8 @@ qrcode==6.0 redis==2.10.6 repoze.lru==0.7 requests==2.19.1 +requirements-detector==0.6 +setoptconf==0.2.0 simplegeneric==0.8.1 simplejson==3.16.0 six==1.11.0 diff --git a/tildes/scripts/initialize_db.py b/tildes/scripts/initialize_db.py index 3df4b27..c7bd111 100644 --- a/tildes/scripts/initialize_db.py +++ b/tildes/scripts/initialize_db.py @@ -1,4 +1,5 @@ """Script for doing the initial setup of database tables.""" +# pylint: disable=wrong-import-order import os import subprocess diff --git a/tildes/tildes/lib/message.py b/tildes/tildes/lib/message.py index 4e422ab..9d4ad7d 100644 --- a/tildes/tildes/lib/message.py +++ b/tildes/tildes/lib/message.py @@ -2,7 +2,6 @@ WELCOME_MESSAGE_SUBJECT = "Welcome to the Tildes alpha" -# pylama:ignore=E501 WELCOME_MESSAGE_TEXT = """ Hi, welcome to the Tildes alpha! diff --git a/tildes/tildes/models/comment/comment_notification_query.py b/tildes/tildes/models/comment/comment_notification_query.py index 32e4d72..b473947 100644 --- a/tildes/tildes/models/comment/comment_notification_query.py +++ b/tildes/tildes/models/comment/comment_notification_query.py @@ -32,6 +32,7 @@ class CommentNotificationQuery(ModelQuery): def join_all_relationships(self) -> "CommentNotificationQuery": """Eagerly join the comment, topic, and group to the notification.""" + # pylint: disable=self-cls-assignment self = self.options( joinedload(CommentNotification.comment) .joinedload("topic") diff --git a/tildes/tildes/models/comment/comment_tree.py b/tildes/tildes/models/comment/comment_tree.py index b4299f6..cdf77e8 100644 --- a/tildes/tildes/models/comment/comment_tree.py +++ b/tildes/tildes/models/comment/comment_tree.py @@ -168,6 +168,7 @@ class CommentTree: direct parents. All comments with any uncollapsed descendant will be collapsed individually. Branches with no uncollapsed comments will be collapsed fully. """ + # pylint: disable=too-many-branches for comment in reversed(self.comments): # as soon as we reach an old comment, we can stop if comment.created_time <= threshold: diff --git a/tildes/tildes/models/log/log.py b/tildes/tildes/models/log/log.py index e7faec5..7b92478 100644 --- a/tildes/tildes/models/log/log.py +++ b/tildes/tildes/models/log/log.py @@ -1,4 +1,5 @@ """Contains the Log class.""" +# pylint: disable=too-many-branches,too-many-return-statements from typing import Any, Dict, Optional @@ -142,7 +143,6 @@ class LogTopic(DatabaseModel, BaseLog): def __str__(self) -> str: """Return a string representation of the log event.""" - # pylint: disable=too-many-return-statements if self.event_type == LogEventType.TOPIC_TAG: return self._tag_event_description() elif self.event_type == LogEventType.TOPIC_MOVE: diff --git a/tildes/tildes/models/model_query.py b/tildes/tildes/models/model_query.py index d0aa06c..69bd114 100644 --- a/tildes/tildes/models/model_query.py +++ b/tildes/tildes/models/model_query.py @@ -1,4 +1,5 @@ """Contains the ModelQuery class, a specialized SQLAlchemy Query subclass.""" +# pylint: disable=self-cls-assignment from typing import Any, Iterator, TypeVar diff --git a/tildes/tildes/models/pagination.py b/tildes/tildes/models/pagination.py index 806f9b7..f3f8a90 100644 --- a/tildes/tildes/models/pagination.py +++ b/tildes/tildes/models/pagination.py @@ -93,6 +93,7 @@ class PaginatedQuery(ModelQuery): def _apply_before_or_after(self) -> "PaginatedQuery": """Apply the "before" or "after" restrictions if necessary.""" + # pylint: disable=assignment-from-no-return if not (self.after_id or self.before_id): return self diff --git a/tildes/tildes/models/topic/topic.py b/tildes/tildes/models/topic/topic.py index 540360c..876a8ed 100644 --- a/tildes/tildes/models/topic/topic.py +++ b/tildes/tildes/models/topic/topic.py @@ -209,6 +209,7 @@ class Topic(DatabaseModel): def __acl__(self) -> Sequence[Tuple[str, Any, str]]: """Pyramid security ACL.""" + # pylint: disable=too-many-branches acl = [] # deleted topics allow "general" viewing, but nothing else diff --git a/tildes/tildes/models/topic/topic_query.py b/tildes/tildes/models/topic/topic_query.py index af7edf7..5273acf 100644 --- a/tildes/tildes/models/topic/topic_query.py +++ b/tildes/tildes/models/topic/topic_query.py @@ -52,6 +52,7 @@ class TopicQuery(PaginatedQuery): def _attach_visit_data(self) -> "TopicQuery": """Join the data related to the user's last visit to the topic(s).""" + # pylint: disable=assignment-from-no-return if self.request.user.track_comment_visits: query = self.outerjoin( TopicVisit, diff --git a/tildes/tildes/schemas/fields.py b/tildes/tildes/schemas/fields.py index 2f43ebd..644e3ae 100644 --- a/tildes/tildes/schemas/fields.py +++ b/tildes/tildes/schemas/fields.py @@ -20,6 +20,7 @@ class Enum(Field): self, enum_class: Optional[Type] = None, *args: Any, **kwargs: Any ) -> None: """Initialize the field with an optional enum class.""" + # pylint: disable=keyword-arg-before-vararg super().__init__(*args, **kwargs) self._enum_class = enum_class diff --git a/tildes/tildes/views/api/web/exceptions.py b/tildes/tildes/views/api/web/exceptions.py index ab9be1a..1261337 100644 --- a/tildes/tildes/views/api/web/exceptions.py +++ b/tildes/tildes/views/api/web/exceptions.py @@ -28,6 +28,7 @@ def _422_response_with_errors(errors: Sequence[str]) -> Response: @ic_view_config(context=ValidationError) def unprocessable_entity(request: Request) -> Response: """Exception view for 422 errors.""" + # pylint: disable=too-many-branches if isinstance(request.exception, ValidationError): validation_error = request.exception else: