Browse Source

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.
merge-requests/34/head
Chad Birch 6 years ago
parent
commit
d170962204
  1. 2
      git_hooks/pre-push
  2. 34
      tildes/prospector.yaml
  3. 69
      tildes/pylama.ini
  4. 6
      tildes/requirements-to-freeze.txt
  5. 18
      tildes/requirements.txt
  6. 1
      tildes/scripts/initialize_db.py
  7. 1
      tildes/tildes/lib/message.py
  8. 1
      tildes/tildes/models/comment/comment_notification_query.py
  9. 1
      tildes/tildes/models/comment/comment_tree.py
  10. 2
      tildes/tildes/models/log/log.py
  11. 1
      tildes/tildes/models/model_query.py
  12. 1
      tildes/tildes/models/pagination.py
  13. 1
      tildes/tildes/models/topic/topic.py
  14. 1
      tildes/tildes/models/topic/topic_query.py
  15. 1
      tildes/tildes/schemas/fields.py
  16. 1
      tildes/tildes/views/api/web/exceptions.py

2
git_hooks/pre-push

@ -6,4 +6,4 @@ vagrant ssh -c ". activate \
&& echo 'Checking mypy type annotations...' && mypy . \ && echo 'Checking mypy type annotations...' && mypy . \
&& echo 'Checking if Black would reformat any code...' && black --check . \ && echo 'Checking if Black would reformat any code...' && black --check . \
&& echo -n 'Running tests: ' && pytest -q \ && 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"

34
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

69
tildes/pylama.ini

@ -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 - <something> 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

6
tildes/requirements-to-freeze.txt

@ -2,7 +2,6 @@ ago
alembic alembic
amqpy amqpy
argon2_cffi argon2_cffi
astroid==1.5.3 # pylama has issues with pylint 1.8.1
black black
bleach bleach
click click
@ -15,12 +14,9 @@ mypy
mypy-extensions mypy-extensions
Pillow Pillow
prometheus-client prometheus-client
prospector
psycopg2 psycopg2
publicsuffix2 publicsuffix2
pydocstyle
pylama
pylama-pylint
pylint==1.7.5 # pylama has issues with 1.8.1
pyotp pyotp
pyramid pyramid
pyramid-debugtoolbar pyramid-debugtoolbar

18
tildes/requirements.txt

@ -3,7 +3,7 @@ alembic==1.0.0
amqpy==0.13.1 amqpy==0.13.1
appdirs==1.4.3 appdirs==1.4.3
argon2-cffi==18.3.0 argon2-cffi==18.3.0
astroid==1.5.3
astroid==2.0.4
atomicwrites==1.2.0 atomicwrites==1.2.0
attrs==18.1.0 attrs==18.1.0
backcall==0.1.0 backcall==0.1.0
@ -16,6 +16,9 @@ chardet==3.0.4
click==6.7 click==6.7
cornice==3.4.0 cornice==3.4.0
decorator==4.3.0 decorator==4.3.0
dodgy==0.1.9
flake8==3.5.0
flake8-polyfill==1.0.2
freezegun==0.3.10 freezegun==0.3.10
gunicorn==19.9.0 gunicorn==19.9.0
html5lib==1.0.1 html5lib==1.0.1
@ -36,6 +39,7 @@ mypy==0.620
mypy-extensions==0.4.1 mypy-extensions==0.4.1
parso==0.3.1 parso==0.3.1
PasteDeploy==1.5.2 PasteDeploy==1.5.2
pep8-naming==0.7.0
pexpect==4.6.0 pexpect==4.6.0
pickleshare==0.7.4 pickleshare==0.7.4
Pillow==5.2.0 Pillow==5.2.0
@ -44,18 +48,18 @@ plaster-pastedeploy==0.6
pluggy==0.7.1 pluggy==0.7.1
prometheus-client==0.3.1 prometheus-client==0.3.1
prompt-toolkit==1.0.15 prompt-toolkit==1.0.15
prospector==1.1.2
psycopg2==2.7.5 psycopg2==2.7.5
ptyprocess==0.6.0 ptyprocess==0.6.0
publicsuffix2==2.20160818 publicsuffix2==2.20160818
py==1.6.0 py==1.6.0
pycodestyle==2.4.0
pycodestyle==2.3.1
pycparser==2.18 pycparser==2.18
pydocstyle==2.1.1 pydocstyle==2.1.1
pyflakes==2.0.0
pyflakes==1.6.0
Pygments==2.2.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 pyotp==2.2.6
pyramid==1.9.2 pyramid==1.9.2
pyramid-debugtoolbar==4.4 pyramid-debugtoolbar==4.4
@ -74,6 +78,8 @@ qrcode==6.0
redis==2.10.6 redis==2.10.6
repoze.lru==0.7 repoze.lru==0.7
requests==2.19.1 requests==2.19.1
requirements-detector==0.6
setoptconf==0.2.0
simplegeneric==0.8.1 simplegeneric==0.8.1
simplejson==3.16.0 simplejson==3.16.0
six==1.11.0 six==1.11.0

1
tildes/scripts/initialize_db.py

@ -1,4 +1,5 @@
"""Script for doing the initial setup of database tables.""" """Script for doing the initial setup of database tables."""
# pylint: disable=wrong-import-order
import os import os
import subprocess import subprocess

1
tildes/tildes/lib/message.py

@ -2,7 +2,6 @@
WELCOME_MESSAGE_SUBJECT = "Welcome to the Tildes alpha" WELCOME_MESSAGE_SUBJECT = "Welcome to the Tildes alpha"
# pylama:ignore=E501
WELCOME_MESSAGE_TEXT = """ WELCOME_MESSAGE_TEXT = """
Hi, welcome to the Tildes alpha! Hi, welcome to the Tildes alpha!

1
tildes/tildes/models/comment/comment_notification_query.py

@ -32,6 +32,7 @@ class CommentNotificationQuery(ModelQuery):
def join_all_relationships(self) -> "CommentNotificationQuery": def join_all_relationships(self) -> "CommentNotificationQuery":
"""Eagerly join the comment, topic, and group to the notification.""" """Eagerly join the comment, topic, and group to the notification."""
# pylint: disable=self-cls-assignment
self = self.options( self = self.options(
joinedload(CommentNotification.comment) joinedload(CommentNotification.comment)
.joinedload("topic") .joinedload("topic")

1
tildes/tildes/models/comment/comment_tree.py

@ -168,6 +168,7 @@ class CommentTree:
direct parents. All comments with any uncollapsed descendant will be collapsed direct parents. All comments with any uncollapsed descendant will be collapsed
individually. Branches with no uncollapsed comments will be collapsed fully. individually. Branches with no uncollapsed comments will be collapsed fully.
""" """
# pylint: disable=too-many-branches
for comment in reversed(self.comments): for comment in reversed(self.comments):
# as soon as we reach an old comment, we can stop # as soon as we reach an old comment, we can stop
if comment.created_time <= threshold: if comment.created_time <= threshold:

2
tildes/tildes/models/log/log.py

@ -1,4 +1,5 @@
"""Contains the Log class.""" """Contains the Log class."""
# pylint: disable=too-many-branches,too-many-return-statements
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
@ -142,7 +143,6 @@ class LogTopic(DatabaseModel, BaseLog):
def __str__(self) -> str: def __str__(self) -> str:
"""Return a string representation of the log event.""" """Return a string representation of the log event."""
# pylint: disable=too-many-return-statements
if self.event_type == LogEventType.TOPIC_TAG: if self.event_type == LogEventType.TOPIC_TAG:
return self._tag_event_description() return self._tag_event_description()
elif self.event_type == LogEventType.TOPIC_MOVE: elif self.event_type == LogEventType.TOPIC_MOVE:

1
tildes/tildes/models/model_query.py

@ -1,4 +1,5 @@
"""Contains the ModelQuery class, a specialized SQLAlchemy Query subclass.""" """Contains the ModelQuery class, a specialized SQLAlchemy Query subclass."""
# pylint: disable=self-cls-assignment
from typing import Any, Iterator, TypeVar from typing import Any, Iterator, TypeVar

1
tildes/tildes/models/pagination.py

@ -93,6 +93,7 @@ class PaginatedQuery(ModelQuery):
def _apply_before_or_after(self) -> "PaginatedQuery": def _apply_before_or_after(self) -> "PaginatedQuery":
"""Apply the "before" or "after" restrictions if necessary.""" """Apply the "before" or "after" restrictions if necessary."""
# pylint: disable=assignment-from-no-return
if not (self.after_id or self.before_id): if not (self.after_id or self.before_id):
return self return self

1
tildes/tildes/models/topic/topic.py

@ -209,6 +209,7 @@ class Topic(DatabaseModel):
def __acl__(self) -> Sequence[Tuple[str, Any, str]]: def __acl__(self) -> Sequence[Tuple[str, Any, str]]:
"""Pyramid security ACL.""" """Pyramid security ACL."""
# pylint: disable=too-many-branches
acl = [] acl = []
# deleted topics allow "general" viewing, but nothing else # deleted topics allow "general" viewing, but nothing else

1
tildes/tildes/models/topic/topic_query.py

@ -52,6 +52,7 @@ class TopicQuery(PaginatedQuery):
def _attach_visit_data(self) -> "TopicQuery": def _attach_visit_data(self) -> "TopicQuery":
"""Join the data related to the user's last visit to the topic(s).""" """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: if self.request.user.track_comment_visits:
query = self.outerjoin( query = self.outerjoin(
TopicVisit, TopicVisit,

1
tildes/tildes/schemas/fields.py

@ -20,6 +20,7 @@ class Enum(Field):
self, enum_class: Optional[Type] = None, *args: Any, **kwargs: Any self, enum_class: Optional[Type] = None, *args: Any, **kwargs: Any
) -> None: ) -> None:
"""Initialize the field with an optional enum class.""" """Initialize the field with an optional enum class."""
# pylint: disable=keyword-arg-before-vararg
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._enum_class = enum_class self._enum_class = enum_class

1
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) @ic_view_config(context=ValidationError)
def unprocessable_entity(request: Request) -> Response: def unprocessable_entity(request: Request) -> Response:
"""Exception view for 422 errors.""" """Exception view for 422 errors."""
# pylint: disable=too-many-branches
if isinstance(request.exception, ValidationError): if isinstance(request.exception, ValidationError):
validation_error = request.exception validation_error = request.exception
else: else:

Loading…
Cancel
Save