From d1709622040bbeadcdd1bd6ec157ca4c4930209b Mon Sep 17 00:00:00 2001 From: Chad Birch Date: Wed, 29 Aug 2018 13:20:50 -0600 Subject: [PATCH] Replace Pylama with Prospector Pylama is no longer maintained, and has been gradually getting slower and slower, as well as being incompatible with Python 3.7 and newer versions of astroid and pylint. This replaces it with Prospector, which is being maintained by the same group as pylint and some other code quality tools. --- git_hooks/pre-push | 2 +- tildes/prospector.yaml | 34 +++++++++ tildes/pylama.ini | 69 ------------------- tildes/requirements-to-freeze.txt | 6 +- tildes/requirements.txt | 18 +++-- tildes/scripts/initialize_db.py | 1 + tildes/tildes/lib/message.py | 1 - .../comment/comment_notification_query.py | 1 + tildes/tildes/models/comment/comment_tree.py | 1 + tildes/tildes/models/log/log.py | 2 +- tildes/tildes/models/model_query.py | 1 + tildes/tildes/models/pagination.py | 1 + tildes/tildes/models/topic/topic.py | 1 + tildes/tildes/models/topic/topic_query.py | 1 + tildes/tildes/schemas/fields.py | 1 + tildes/tildes/views/api/web/exceptions.py | 1 + 16 files changed, 58 insertions(+), 83 deletions(-) create mode 100644 tildes/prospector.yaml delete mode 100644 tildes/pylama.ini 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: