Просмотр исходного кода

Merge pull request #499 from justanr/tox-travis-changes

Run linting as a standalone tox task
Peter Justin 6 лет назад
Родитель
Сommit
cc58e86555

+ 19 - 3
.travis.yml

@@ -1,15 +1,31 @@
 language: python
+python:
+  - 2.7
+  - 3.4
+  - 3.5
+  - 3.6
+env:
 matrix:
+  fast_finish: true
   include:
     - python: 2.7
-    - python: 3.4
-    - python: 3.5
+      env: TOXENV=py27-unpinned
     - python: 3.6
+      env: TOXENV=flake8
+    - python: 3.6
+      env: TOXENV=py36-unpinned
+    - python: 3.6
+      env: TOXENV=black
     # see the following issue on why 3.7 is weirdo
     # https://github.com/travis-ci/travis-ci/issues/9815
     - python: 3.7
       dist: xenial
       sudo: true
+  allow_failures:
+    # until the entire code base is properly formatted
+    # allow failures to occur here rather than doing a
+    # big all at once reformat that could hide errors
+    - env: TOXENV=black
 install:
 - pip install -r requirements-travis.txt
 script:
@@ -31,4 +47,4 @@ deploy:
     tags: true
     all_branches: true
     repo: flaskbb/flaskbb
-    python: '3.6'
+    python: '3.7'

+ 7 - 5
flaskbb/core/auth/authentication.py

@@ -150,7 +150,7 @@ class PostAuthenticationHandler(ABC):
     their account.
 
     Cancelling a successful authentication will cause registered
-    :class:`AuthenticationFailureHandler<flaskbb.core.auth.authentication.AuthenticationFailureHandler>`
+    :class:`~flaskbb.core.auth.authentication.AuthenticationFailureHandler`
     instances to be run.
 
     Success handlers should not return a value as it will not be considered.
@@ -179,6 +179,7 @@ class ReauthenticateManager(ABC):
     Unlike the AuthenticationManager, there is no need to return the user to
     the caller.
     """
+
     @abstractmethod
     def reauthenticate(self, user, secret):
         """
@@ -200,7 +201,7 @@ class ReauthenticateProvider(ABC):
     for example when suspicious activity is detected in their session.
 
     ReauthenticateProviders are similiar to
-    :class:`AuthenticationProvider<flaskbb.core.auth.authentication.AuthenticationProvider>`
+    :class:`~flaskbb.core.auth.authentication.AuthenticationProvider`
     except they receive a user instance rather than an identifer for a user.
 
     A successful reauthentication should return True while failures should
@@ -208,7 +209,7 @@ class ReauthenticateProvider(ABC):
 
     If a ReauthenticateProvider determines that reauthentication should
     immediately end, it may raise
-    :class:`StopAuthentication<flaskbb.core.auth.authentication.StopAuthentication>`
+    :class:~flaskbb.core.auth.authentication.StopAuthentication`
     to safely end the process.
 
 
@@ -250,9 +251,10 @@ class ReauthenticateFailureHandler(ABC):
     Used to manager reauthentication failures in FlaskBB.
 
     ReauthenticateFailureHandlers are similiar to
-    :class:`AuthenticationFailureHandler<flaskbb.core.auth.authentication.AuthenticationFailureHandler>`
+    :class:`~flaskbb.core.auth.authentication.AuthenticationFailureHandler`
     except they receive the user instance rather than an indentifier for a user
     """
+
     @abstractmethod
     def handle_reauth_failure(self, user):
         """
@@ -272,7 +274,7 @@ class PostReauthenticateHandler(ABC):
     Used to post process successful reauthentication attempts.
 
     PostAuthenticationHandlers are similar to
-    :class:`PostAuthenticationHandler<flaskbb.core.auth.authentication.PostAuthenticationHandler>`,
+    :class:`~flaskbb.core.auth.authentication.PostAuthenticationHandler`,
     including their ability to cancel a successful attempt by raising
     :class:`StopAuthentication<flaskbb.core.auth.authentication.StopAuthentication>`
     """

+ 1 - 1
flaskbb/forum/views.py

@@ -327,7 +327,7 @@ class ManageForum(MethodView):
         )
 
     # TODO(anr): Clean this up. @_@
-    def post(self, forum_id, slug=None):
+    def post(self, forum_id, slug=None):  # noqa: C901
         forum_instance, __ = Forum.get_forum(
             forum_id=forum_id, user=real(current_user)
         )

+ 4 - 1
flaskbb/tokens/serializer.py

@@ -15,6 +15,9 @@ from itsdangerous import (BadData, BadSignature, SignatureExpired,
 from ..core import tokens
 
 
+_DEFAULT_EXPIRY = timedelta(hours=1)
+
+
 class FlaskBBTokenSerializer(tokens.TokenSerializer):
     """
     Default token serializer for FlaskBB. Generates JWTs
@@ -33,7 +36,7 @@ class FlaskBBTokenSerializer(tokens.TokenSerializer):
     :timedelta expiry: Expiration of tokens
     """
 
-    def __init__(self, secret_key, expiry=timedelta(hours=1)):
+    def __init__(self, secret_key, expiry=_DEFAULT_EXPIRY):
         self._serializer = TimedJSONWebSignatureSerializer(
             secret_key, int(expiry.total_seconds())
         )

+ 2 - 2
flaskbb/utils/database.py

@@ -126,7 +126,7 @@ class HideableMixin(object):
     hidden_at = db.Column(UTCDateTime(timezone=True), nullable=True)
 
     @declared_attr
-    def hidden_by_id(cls):
+    def hidden_by_id(cls):  # noqa: B902
         return db.Column(
             db.Integer,
             db.ForeignKey(
@@ -136,7 +136,7 @@ class HideableMixin(object):
         )
 
     @declared_attr
-    def hidden_by(cls):
+    def hidden_by(cls):  # noqa: B902
         return db.relationship(
             "User", uselist=False, foreign_keys=[cls.hidden_by_id]
         )

+ 6 - 2
flaskbb/utils/fields.py

@@ -159,16 +159,20 @@ class SelectBirthdayWidget(object):
         '%Y': 'select_date_year'
     }
 
-    def __init__(self, years=range(1930, datetime.utcnow().year + 1)):
+    def __init__(self, years=None):
         """Initialzes the widget.
 
         :param years: The min year which should be chooseable.
                       Defatuls to ``1930``.
         """
+        if years is None:
+            years = range(1930, datetime.utcnow().year + 1)
+
         super(SelectBirthdayWidget, self).__init__()
         self.FORMAT_CHOICES['%Y'] = [(x, str(x)) for x in years]
 
-    def __call__(self, field, **kwargs):
+    # TODO(anr): clean up
+    def __call__(self, field, **kwargs):  # noqa: C901
         field_id = kwargs.pop('id', field.id)
         html = []
         allowed_format = ['%d', '%m', '%Y']

+ 2 - 1
flaskbb/utils/forms.py

@@ -58,7 +58,8 @@ def populate_settings_form(form, settings):
     return form
 
 
-def generate_settings_form(settings):
+# TODO(anr): clean this up
+def generate_settings_form(settings):  # noqa: C901
     """Generates a settings form which includes field validation
     based on our Setting Schema."""
     class SettingsForm(FlaskBBForm):

+ 2 - 1
flaskbb/utils/helpers.py

@@ -92,7 +92,8 @@ def render_template(template, **context):  # pragma: no cover
     return render_theme_template(theme, template, **context)
 
 
-def do_topic_action(topics, user, action, reverse):
+# TODO(anr): clean this up
+def do_topic_action(topics, user, action, reverse):  # noqa: C901
     """Executes a specific action for topics. Returns a list with the modified
     topic objects.
 

+ 3 - 8
flaskbb/utils/populate.py

@@ -279,11 +279,6 @@ def create_test_data(users=5, categories=2, forums=2, topics=1, posts=1):
     user1 = User.query.filter_by(id=1).first()
     user2 = User.query.filter_by(id=2).first()
 
-    # lets send them a few private messages
-    for i in range(1, 3):
-        # TODO
-        pass
-
     # create 2 categories
     for i in range(1, categories + 1):
         category_title = "Test Category %s" % i
@@ -303,7 +298,7 @@ def create_test_data(users=5, categories=2, forums=2, topics=1, posts=1):
             forum.save()
             data_created['forums'] += 1
 
-            for t in range(1, topics + 1):
+            for _ in range(1, topics + 1):
                 # create a topic
                 topic = Topic(title="Test Title %s" % j)
                 post = Post(content="Test Content")
@@ -311,7 +306,7 @@ def create_test_data(users=5, categories=2, forums=2, topics=1, posts=1):
                 topic.save(post=post, user=user1, forum=forum)
                 data_created['topics'] += 1
 
-                for p in range(1, posts + 1):
+                for _ in range(1, posts + 1):
                     # create a second post in the forum
                     post = Post(content="Test Post")
                     post.save(user=user2, topic=topic)
@@ -354,7 +349,7 @@ def insert_bulk_data(topic_count=10, post_count=100):
         created_topics += 1
 
         # create some posts in the topic
-        for j in range(1, post_count + 1):
+        for _ in range(1, post_count + 1):
             last_post_id += 1
             post = Post(content="Some other Post", user=user2, topic=topic.id)
             topic.last_updated = post.date_created

+ 1 - 1
requirements-cov.txt

@@ -1 +1 @@
-coverage==4.5.1
+coverage>=4.5.1

+ 2 - 2
requirements-dev.txt

@@ -7,5 +7,5 @@ pytest-cov
 Sphinx
 alabaster
 flake8
-tox==3.0.0
-bumpversion==0.5.3
+tox>=3.0.0
+bumpversion>=0.5.3

+ 2 - 0
requirements-lint.txt

@@ -0,0 +1,2 @@
+flake8>=3.5.0
+flake8-bugbear>=18.2.0

+ 2 - 4
requirements-test.txt

@@ -1,7 +1,5 @@
--rrequirements.txt
 -rrequirements-cov.txt
-flake8==3.5.0
-pytest==3.6.2
-pytest-flake8==1.0.1
+pytest==3.6.4
 pytest-mock==1.10.0
 freezegun==0.3.10
+mock==2.0.0 ; python_version<'3.3'

+ 3 - 3
requirements-travis.txt

@@ -1,4 +1,4 @@
 -r requirements-cov.txt
--r requirements.txt
-tox-travis==0.10
-coveralls==1.3.0
+-rrequirements.txt
+tox-travis>=0.10
+coveralls>=1.3.0

+ 1 - 1
requirements.txt

@@ -9,7 +9,7 @@ certifi==2018.4.16
 chardet==3.0.4
 click==6.7
 click-log==0.3.2
-enum34==1.1.6
+enum34==1.1.6 ; python_version<'3.4'
 Flask==1.0.2
 Flask-Alembic==2.0.1
 flask-allows==0.6.0

+ 1 - 1
setup.py

@@ -46,7 +46,7 @@ install_requires = [
     "chardet>=3.0.4",
     "click>=6.7",
     "click-log>=0.3.2",
-    "enum34>=1.1.6",
+    "enum34>=1.1.6 ; python_version<'3.4'",
     "Flask>=1.0.2",
     "Flask-Alembic>=2.0.1",
     "flask-allows>=0.6.0",

+ 36 - 5
tox.ini

@@ -1,17 +1,26 @@
 [tox]
-envlist = py27,py34,py35,py36,py37,cov-report,cov-store
+envlist = flake8,py{27,34,35,36,37},cov-report,cov-store
 
 [testenv]
 use_develop = true
 deps =
-    py27: mock==2.0.0
     -r{toxinidir}/requirements-test.txt
+    # setup.py has unpinned dependencies by default
+    !unpinned: -r{toxinidir}/requirements.txt
 setenv =
     COVERAGE_FILE = tests/.coverage.{envname}
     PYTHONDONTWRITEBYTECODE=1
 commands =
     coverage run -m pytest {toxinidir}/tests {toxinidir}/flaskbb {posargs}
 
+[testenv:flake8]
+skip_install = true
+deps = -r{toxinidir}/requirements-lint.txt
+basepython=python3.6
+commands =
+    flake8 --version
+    flake8 --config={toxinidir}/tox.ini {toxinidir}/flaskbb {toxinidir}/tests
+
 [testenv:cov-report]
 skip_install = true
 setenv =
@@ -32,12 +41,34 @@ commands =
     coverage html
 
 
+[testenv:black]
+skip_install = true
+deps = black
+basepython=python3.6
+commands = black --check tests/ flaskbb/
+
 [flake8]
-ignore = E712, E711, C901, W503
+ignore = E203, E712, E711, W503
+select = C,E,F,W,B,B9
 max-complexity = 10
 max-line-length = 88
-exclude = flaskbb/configs/default.py,flaskbb/_compat.py
+exclude =
+    # allowed to break the rules
+    flaskbb/configs/default.py,
+    flaskbb/_compat.py,
+    # migrations are autogenerated
+    migrations,
+    # stuff to not inspect at all
+    node_modules,
+    .git,
+    .tox,
+    *.pyc,
+    __pycache__,
+    instance,
+    dist,
+    build,
+    docs
 
 [pytest]
-addopts =  -vvl --strict --flake8 --capture fd -W error::flaskbb.deprecation.FlaskBBDeprecation
+addopts =  -vvl --strict --capture fd -W error::flaskbb.deprecation.FlaskBBDeprecation
 norecursedirs = node_modules