Add flake8 linting to project

The GDS Way™[1] recommends using Flake8 to lint Python projects.

This commit takes the Flake8 config from Digital Marketplace API[2] and
removes the bits we don’t need.

It changes the `max_complexity` setting to 14, which is the most complex
code we have in this repo currently (we shouldn’t be writing code _more_
complex than what we already have).

This commit also fixes the errors found by Flake8, which includes 6(!)
tests which were never getting run because they had the same names as
existing tests.

Here is a full list of the errors that were found and fixed:
```
./app/__init__.py:2:1: F401 're' imported but unused
./app/__init__.py:4:1: F401 'json' imported but unused
./app/__init__.py:8:1: F401 'dateutil' imported but unused
./app/__init__.py:11:1: F401 'flask.escape' imported but unused
./app/__init__.py:41:1: F401 'app.proxy_fix' imported but unused
./app/__init__.py:129:5: F821 undefined name 'proxy_fix'
./app/__init__.py:221:19: F821 undefined name 'highlight'
./app/__init__.py:221:35: F821 undefined name 'JavascriptLexer'
./app/__init__.py:221:54: F821 undefined name 'HtmlFormatter'
./app/config.py:2:1: F401 'datetime.timedelta' imported but unused
./app/event_handlers.py:2:1: F401 'flask_login.current_user' imported but unused
./app/utils.py:11:1: F401 'dateutil.parser' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.two_factor' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.notifications' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.add_service' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.forgot_password' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.inbound_number' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.styleguide' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.organisations' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.letter_jobs' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.verify' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.conversation' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.api_keys' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.send' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.dashboard' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.jobs' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.manage_users' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.sign_in' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.sign_out' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.code_not_received' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.invites' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.platform_admin' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.providers' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.service_settings' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.index' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.new_password' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.user_profile' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.feedback' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.choose_service' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.templates' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.register' imported but unused
./app/main/forms.py:12:1: F401 'wtforms.SelectField' imported but unused
./app/main/views/api_keys.py:37:29: E241 multiple spaces after ':'
./app/main/views/feedback.py:3:1: F401 'flask.flash' imported but unused
./app/main/views/feedback.py:122:17: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/inbound_number.py:1:1: F401 'flask.url_for' imported but unused
./app/main/views/inbound_number.py:1:1: F401 'flask.session' imported but unused
./app/main/views/inbound_number.py:1:1: F401 'flask.redirect' imported but unused
./app/main/views/inbound_number.py:1:1: F401 'flask.request' imported but unused
./app/main/views/inbound_number.py:13:1: F401 'flask.jsonify' imported but unused
./app/main/views/jobs.py:31:1: F401 'app.utils.get_template' imported but unused
./app/main/views/letter_jobs.py:1:1: F401 'datetime' imported but unused
./app/main/views/letter_jobs.py:6:1: F401 'app.format_datetime_24h' imported but unused
./app/main/views/manage_users.py:111:9: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/notifications.py:121:5: F841 local variable 'status_args' is assigned to but never used
./app/main/views/organisations.py:1:1: F401 'flask.request' imported but unused
./app/main/views/service_settings.py:77:9: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/service_settings.py:82:9: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/service_settings.py:420:13: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/sign_in.py:12:1: F401 'flask_login.confirm_login' imported but unused
./app/main/views/sign_in.py:17:1: F401 'app.service_api_client' imported but unused
./app/main/views/sign_in.py:62:13: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/templates.py:4:1: F401 'flask.json' imported but unused
./app/main/views/templates.py:17:1: F401 'notifications_utils.formatters.escape_html' imported but unused
./app/main/views/templates.py:23:1: F401 'app.utils.get_help_argument' imported but unused
./app/main/views/templates.py:64:13: E123 closing bracket does not match indentation of opening bracket's line
./app/notify_client/service_api_client.py:6:1: F401 '.notification_api_client' imported but unused
./app/notify_client/user_api_client.py:1:1: F401 'uuid' imported but unused
./app/notify_client/user_api_client.py:3:1: F401 'flask.session' imported but unused
./tests/__init__.py:1:1: F401 'csv' imported but unused
./tests/app/main/test_asset_fingerprinter.py:2:1: F401 'os' imported but unused
./tests/app/main/test_asset_fingerprinter.py:4:1: F401 'unittest.mock' imported but unused
./tests/app/main/test_asset_fingerprinter.py:98:9: F841 local variable 'string_with_unicode_character' is assigned to but never used
./tests/app/main/test_errorhandlers.py:2:1: F401 'flask.url_for' imported but unused
./tests/app/main/test_permissions.py:26:13: F841 local variable 'response' is assigned to but never used
./tests/app/main/test_placeholder_form.py:3:1: F401 'wtforms.Label' imported but unused
./tests/app/main/test_placeholder_form.py:11:10: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:10:67: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:23:65: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:37:48: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:51:67: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:65:67: F841 local variable 'req' is assigned to but never used
./tests/app/main/views/test_accept_invite.py:356:5: F841 local variable 'element' is assigned to but never used
./tests/app/main/views/test_activity.py:11:1: F811 redefinition of unused 'mock_get_notifications' from line 11
./tests/app/main/views/test_activity.py:18:1: F401 'datetime.datetime' imported but unused
./tests/app/main/views/test_activity.py:102:5: F841 local variable 'content' is assigned to but never used
./tests/app/main/views/test_activity.py:104:5: F841 local variable 'notification' is assigned to but never used
./tests/app/main/views/test_activity.py:337:5: F841 local variable '_notifications_mock' is assigned to but never used
./tests/app/main/views/test_activity.py:373:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_activity.py:378:9: E121 continuation line under-indented for hanging indent
./tests/app/main/views/test_activity.py:404:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_activity.py:407:9: E121 continuation line under-indented for hanging indent
./tests/app/main/views/test_api_keys.py:354:5: F841 local variable 'response' is assigned to but never used
./tests/app/main/views/test_conversation.py:5:1: F401 'bs4.BeautifulSoup' imported but unused
./tests/app/main/views/test_conversation.py:198:5: F841 local variable 'mock_get_inbound_sms' is assigned to but never used
./tests/app/main/views/test_dashboard.py:53:5: F841 local variable 'mock_template_stats' is assigned to but never used
./tests/app/main/views/test_dashboard.py:72:5: F841 local variable 'mock_template_stats' is assigned to but never used
./tests/app/main/views/test_jobs.py:2:1: F401 'uuid' imported but unused
./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.urlparse' imported but unused
./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.quote' imported but unused
./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.parse_qs' imported but unused
./tests/app/main/views/test_jobs.py:9:1: F401 'app.main.views.jobs.get_status_filters' imported but unused
./tests/app/main/views/test_jobs.py:10:1: F401 'tests.notification_json' imported but unused
./tests/app/main/views/test_letters.py:6:1: F401 'tests.service_json' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.REQUESTED_STATUSES' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.DELIVERED_STATUSES' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.SENDING_STATUSES' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.FAILURE_STATUSES' imported but unused
./tests/app/main/views/test_platform_admin.py:242:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_platform_admin.py:247:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_send.py:3:1: F401 'unittest.mock.Mock' imported but unused
./tests/app/main/views/test_send.py:18:1: F811 redefinition of unused 'mock_get_service' from line 18
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.multiple_letter_contact_blocks' imported but unused
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.no_sms_senders' imported but unused
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.multiple_sms_senders' imported but unused
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.no_letter_contact_blocks' imported but unused
./tests/app/main/views/test_send.py:102:5: F841 local variable 'response' is assigned to but never used
./tests/app/main/views/test_send.py:870:5: F841 local variable 'response' is assigned to but never used
./tests/app/main/views/test_send.py:1367:5: F841 local variable 'service_id' is assigned to but never used
./tests/app/main/views/test_send.py:1451:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_send.py:1620:80: E226 missing whitespace around arithmetic operator
./tests/app/main/views/test_send.py:1909:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_send.py:1912:9: E121 continuation line under-indented for hanging indent
./tests/app/main/views/test_service_settings.py:13:1: F811 redefinition of unused 'no_reply_to_email_addresses' from line 13
./tests/app/main/views/test_service_settings.py:13:1: F401 'tests.conftest.single_reply_to_email_address' imported but unused
./tests/app/main/views/test_service_settings.py:28:5: E123 closing bracket does not match indentation of opening bracket's line
./tests/app/main/views/test_service_settings.py:104:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:166:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:186:5: F841 local variable 'mocked_get_fn' is assigned to but never used
./tests/app/main/views/test_service_settings.py:217:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:237:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:257:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:307:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:340:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:466:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:555:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:615:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:719:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:874:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:902:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:954:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:986:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1101:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1121:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1271:1: F811 redefinition of unused 'test_set_letter_contact_block_saves' from line 1189
./tests/app/main/views/test_service_settings.py:1433:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1495:5: F841 local variable 'mocked_get_fn' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1540:5: F841 local variable 'mocked_get_fn' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1570:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1589:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1621:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1641:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1658:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1676:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1697:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1759:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1775:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_templates.py:3:1: F401 'uuid' imported but unused
./tests/app/main/views/test_templates.py:11:1: F401 'tests.conftest.mock_get_user' imported but unused
./tests/app/main/views/test_templates.py:514:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_templates.py:672:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_templates.py:795:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_templates.py:835:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_two_factor.py:67:13: E126 continuation line over-indented for hanging indent
./tests/app/notify_client/test_notification_client.py:79:5: F841 local variable 'mock_post' is assigned to but never used
```

1. https://gds-way.cloudapps.digital/manuals/programming-languages/python/linting.html#how-to-use-flake8
2. https://github.com/alphagov/digitalmarketplace-api/blob/d5ab8afef4a0472f9d266d94ab4ffe1333a9aaad/.flake8
This commit is contained in:
Chris Hill-Scott
2017-10-20 11:02:39 +01:00
parent 02216b106e
commit 2cecadfcbc
42 changed files with 260 additions and 302 deletions
+7
View File
@@ -0,0 +1,7 @@
[flake8]
# Rule definitions: http://flake8.pycqa.org/en/latest/user/error-codes.html
# W503: line break before binary operator
exclude = venv*,__pycache__,node_modules,cache
ignore = W503
max-complexity = 14
max-line-length = 120
+3 -12
View File
@@ -1,24 +1,20 @@
import os
import re
import urllib
import json
from datetime import datetime, timedelta, timezone
from time import monotonic
import dateutil
import itertools
import ago
from flask import (
Flask,
session,
Markup,
escape,
render_template,
make_response,
current_app,
request,
g,
url_for)
url_for
)
from flask._compat import string_types
from flask.globals import _lookup_req_object, _request_ctx_stack
from flask_login import LoginManager
@@ -38,7 +34,7 @@ from notifications_utils.formatters import formatted_list
from werkzeug.exceptions import abort
from werkzeug.local import LocalProxy
import app.proxy_fix
from app import proxy_fix
from app.asset_fingerprinter import AssetFingerprinter
from app.its_dangerous_session import ItsdangerousSessionInterface
from app.notify_client.service_api_client import ServiceAPIClient
@@ -135,7 +131,6 @@ def create_app():
application.add_template_filter(format_datetime_normal)
application.add_template_filter(format_datetime_short)
application.add_template_filter(format_time)
application.add_template_filter(syntax_highlight_json)
application.add_template_filter(valid_phone_number)
application.add_template_filter(linkable_name)
application.add_template_filter(format_date)
@@ -217,10 +212,6 @@ def linkable_name(value):
return urllib.parse.quote_plus(value)
def syntax_highlight_json(code):
return Markup(highlight(code, JavascriptLexer(), HtmlFormatter(noclasses=True)))
def format_datetime(date):
return '{} at {}'.format(
format_date(date),
-1
View File
@@ -1,5 +1,4 @@
import os
from datetime import timedelta
if os.environ.get('VCAP_SERVICES'):
-1
View File
@@ -1,5 +1,4 @@
from app import events_api_client
from flask_login import current_user
def on_user_logged_in(sender, user):
+1 -1
View File
@@ -2,7 +2,7 @@ from flask import Blueprint
main = Blueprint('main', __name__) # noqa
from app.main.views import (
from app.main.views import ( # noqa
index,
sign_in,
sign_out,
+1 -1
View File
@@ -23,7 +23,7 @@ from wtforms import (
RadioField,
FieldList,
DateField,
SelectField)
)
from wtforms.fields.html5 import EmailField, TelField, SearchField
from wtforms.validators import (DataRequired, Email, Length, Regexp, Optional)
from flask_wtf.file import FileField as FileField_wtf, FileAllowed
-1
View File
@@ -21,7 +21,6 @@ from app import (
service_api_client,
template_statistics_client,
inbound_number_client,
format_datetime_short,
format_date_numeric,
format_datetime_numeric,
)
+3 -2
View File
@@ -1,6 +1,6 @@
import requests
import pytz
from flask import render_template, url_for, redirect, flash, current_app, abort, request, session
from flask import render_template, url_for, redirect, current_app, abort, request, session
from flask_login import current_user
from app import convert_to_boolean, current_service, service_api_client
from app.main import main
@@ -118,7 +118,8 @@ def feedback(ticket_type):
current_app.logger.error(
"Deskpro create ticket request failed with {} '{}'".format(
resp.status_code,
resp.json())
resp.json()
)
)
abort(500, "Feedback submission failed")
return redirect(url_for('.thanks', urgent=urgent, anonymous=anonymous))
+1 -9
View File
@@ -1,16 +1,8 @@
from flask import (
render_template,
redirect,
session,
url_for,
request
)
from flask import render_template
from flask_login import login_required
from app.main import main
from app import inbound_number_client
from app.utils import user_has_permissions
from flask import jsonify
@main.route('/inbound-sms-admin', methods=['GET', 'POST'])
-1
View File
@@ -34,7 +34,6 @@ from app.utils import (
generate_previous_dict,
user_has_permissions,
generate_notifications_csv,
get_template,
get_time_left,
REQUESTED_STATUSES,
FAILURE_STATUSES,
+1 -3
View File
@@ -1,9 +1,7 @@
import datetime
from flask import redirect, render_template, request, session, url_for
from flask_login import login_required
from app import letter_jobs_client, format_datetime_24h
from app import letter_jobs_client
from app.main import main
from app.utils import user_has_permissions
-2
View File
@@ -118,8 +118,6 @@ def view_notification_updates(service_id, notification_id):
def get_single_notification_partials(notification):
status_args = get_status_arg(request.args)
return {
'notifications': render_template(
'partials/notifications/notifications.html',
+1 -1
View File
@@ -1,4 +1,4 @@
from flask import current_app, redirect, render_template, session, url_for, request
from flask import current_app, redirect, render_template, session, url_for
from flask_login import login_required
from app import organisations_client
+2 -3
View File
@@ -11,13 +11,11 @@ from flask import (
from flask_login import (
current_user,
confirm_login
)
from app import (
login_manager,
user_api_client,
service_api_client,
invite_api_client
)
@@ -56,7 +54,8 @@ def sign_in():
else:
return redirect(url_for('.two_factor'))
# Vague error message for login in case of user not known, locked, inactive or password not verified
flash(Markup((
flash(Markup(
(
"The email address or password you entered is incorrect."
" <a href={password_reset}>Forgot your password</a>?"
).format(password_reset=url_for('.forgot_password'))
+1 -3
View File
@@ -8,19 +8,17 @@ from flask import (
url_for,
flash,
abort,
json,
Response,
)
from flask_login import login_required, current_user
from dateutil.parser import parse
from notifications_utils.formatters import escape_html
from notifications_utils.recipients import first_column_headings
from notifications_utils.template import LetterDVLATemplate
from notifications_python_client.errors import HTTPError
from app.main import main
from app.utils import user_has_permissions, get_template, get_help_argument, email_or_sms_not_enabled
from app.utils import user_has_permissions, get_template, email_or_sms_not_enabled
from app.template_previews import TemplatePreview, get_page_count_for_letter
from app.main.forms import (
ChooseTemplateType,
-1
View File
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
from flask import url_for
from app.utils import BrowsableItem
from app.notify_client import _attach_current_user, NotifyAdminAPIClient
from . import notification_api_client
class ServiceAPIClient(NotifyAdminAPIClient):
-3
View File
@@ -1,6 +1,3 @@
import uuid
from flask import session
from notifications_python_client.errors import HTTPError
from app.notify_client import NotifyAdminAPIClient
-1
View File
@@ -8,7 +8,6 @@ import unicodedata
from urllib.parse import urlparse
from collections import namedtuple
from datetime import datetime, timedelta, timezone
from dateutil import parser
import dateutil
import ago
+1 -1
View File
@@ -1,5 +1,4 @@
-r requirements.txt
pycodestyle==2.3.1
pytest==3.2.3
pytest-mock==1.6.3
pytest-cov==2.5.1
@@ -8,3 +7,4 @@ coveralls==1.2.0
httpretty==0.8.14
beautifulsoup4==4.6.0
freezegun==0.3.9
flake8==3.4.1
-1
View File
@@ -1,4 +1,3 @@
import csv
import pytest
import uuid
+1 -4
View File
@@ -1,7 +1,4 @@
# coding=utf-8
import os
from unittest import mock
from app.asset_fingerprinter import AssetFingerprinter
@@ -95,5 +92,5 @@ class TestAssetFingerprint(object):
class TestAssetFingerprintWithUnicode(object):
def test_can_read_self(self):
string_with_unicode_character = 'Ralphs apostrophe'
'Ralphs apostrophe is a string containing a unicode character'
AssetFingerprinter(filesystem_path='tests/app/main/').get_url('test_asset_fingerprinter.py')
-1
View File
@@ -1,5 +1,4 @@
from bs4 import BeautifulSoup
from flask import url_for
def test_bad_url_returns_page_not_found(client):
+2 -2
View File
@@ -20,10 +20,10 @@ def _test_permissions(
decorator = user_has_permissions(*permissions, any_=any_, admin_override=admin_override)
decorated_index = decorator(index)
if will_succeed:
response = decorated_index()
decorated_index()
else:
try:
response = decorated_index()
decorated_index()
pytest.fail("Failed to throw a forbidden or unauthorised exception")
except (Forbidden, Unauthorized):
pass
+1 -2
View File
@@ -1,6 +1,5 @@
import pytest
from app.main.forms import get_placeholder_form_instance
from wtforms import Label
def test_form_class_not_mutated(app_):
@@ -8,7 +7,7 @@ def test_form_class_not_mutated(app_):
with app_.test_request_context(
method='POST',
data={'placeholder_value': ''}
) as req:
):
form1 = get_placeholder_form_instance('name', {}, optional_placeholder=False)
form2 = get_placeholder_form_instance('city', {}, optional_placeholder=True)
+20 -10
View File
@@ -6,8 +6,10 @@ def test_form_is_valid_returns_no_errors(
app_,
mock_check_verify_code,
):
with app_.test_request_context(method='POST',
data={'sms_code': '12345'}) as req:
with app_.test_request_context(
method='POST',
data={'sms_code': '12345'}
):
def _check_code(code):
return user_api_client.check_verify_code('1', code, "sms")
form = TwoFactorForm(_check_code)
@@ -19,8 +21,10 @@ def test_returns_errors_when_code_is_too_short(
app_,
mock_check_verify_code,
):
with app_.test_request_context(method='POST',
data={'sms_code': '145'}) as req:
with app_.test_request_context(
method='POST',
data={'sms_code': '145'}
):
def _check_code(code):
return user_api_client.check_verify_code('1', code, "sms")
form = TwoFactorForm(_check_code)
@@ -33,8 +37,10 @@ def test_returns_errors_when_code_is_missing(
app_,
mock_check_verify_code,
):
with app_.test_request_context(method='POST',
data={}) as req:
with app_.test_request_context(
method='POST',
data={}
):
def _check_code(code):
return user_api_client.check_verify_code('1', code, "sms")
form = TwoFactorForm(_check_code)
@@ -47,8 +53,10 @@ def test_returns_errors_when_code_contains_letters(
app_,
mock_check_verify_code,
):
with app_.test_request_context(method='POST',
data={'sms_code': 'asdfg'}) as req:
with app_.test_request_context(
method='POST',
data={'sms_code': 'asdfg'}
):
def _check_code(code):
return user_api_client.check_verify_code('1', code, "sms")
form = TwoFactorForm(_check_code)
@@ -61,8 +69,10 @@ def test_should_return_errors_when_code_is_expired(
app_,
mock_check_verify_code_code_expired,
):
with app_.test_request_context(method='POST',
data={'sms_code': '23456'}) as req:
with app_.test_request_context(
method='POST',
data={'sms_code': '23456'}
):
def _check_code(code):
return user_api_client.check_verify_code('1', code, "sms")
form = TwoFactorForm(_check_code)
+1 -1
View File
@@ -353,4 +353,4 @@ def test_new_invited_user_verifies_and_added_to_service(
raw_html = response.data.decode('utf-8')
page = BeautifulSoup(raw_html, 'html.parser')
element = page.find('h2').text == 'Trial mode'
assert page.find('h1').text == 'Dashboard'
+1 -7
View File
@@ -7,15 +7,12 @@ from flask import url_for
from bs4 import BeautifulSoup
from app.main.views.jobs import get_time_left, get_status_filters
from tests import notification_json
from tests.conftest import (
SERVICE_ONE_ID,
mock_get_notifications,
normalize_spaces,
mock_get_notifications
)
from freezegun import freeze_time
from datetime import datetime
@pytest.mark.parametrize(
@@ -99,9 +96,6 @@ def test_can_show_notifications(
))
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
content = response.get_data(as_text=True)
notifications = notification_json(service_one['id'])
notification = notifications['notifications'][0]
text_of_first_row = page.select('tbody tr')[0].text
assert '07123456789' in text_of_first_row
assert (
@@ -334,7 +328,7 @@ def test_redacts_templates_that_should_be_redacted(
active_user_with_permissions,
mock_get_detailed_service,
):
_notifications_mock = mock_get_notifications(
mock_get_notifications(
mocker,
active_user_with_permissions,
template_content="hello ((name))",
+1 -1
View File
@@ -351,7 +351,7 @@ def test_should_update_whitelist(
('phone_numbers-2', '+1800-555-555'),
])
response = logged_in_client.post(
logged_in_client.post(
url_for('main.whitelist', service_id=service_id),
data=data
)
+1 -1
View File
@@ -2,7 +2,6 @@ from datetime import datetime
import json
import pytest
from bs4 import BeautifulSoup
from flask import (
url_for,
)
@@ -214,6 +213,7 @@ def test_view_conversation_with_empty_inbound(
messages = page.select('.sms-message-wrapper')
assert len(messages) == 1
assert mock_get_inbound_sms.called is True
def test_conversation_links_to_reply(
+8 -4
View File
@@ -51,8 +51,10 @@ def test_get_started(
mock_get_usage,
mock_get_inbound_sms_summary
):
mock_template_stats = mocker.patch('app.template_statistics_client.get_template_statistics_for_service',
return_value=copy.deepcopy(stub_template_stats))
mocker.patch(
'app.template_statistics_client.get_template_statistics_for_service',
return_value=copy.deepcopy(stub_template_stats)
)
response = logged_in_client.get(url_for('main.service_dashboard', service_id=SERVICE_ONE_ID))
@@ -70,8 +72,10 @@ def test_get_started_is_hidden_once_templates_exist(
mock_get_usage,
mock_get_inbound_sms_summary
):
mock_template_stats = mocker.patch('app.template_statistics_client.get_template_statistics_for_service',
return_value=copy.deepcopy(stub_template_stats))
mocker.patch(
'app.template_statistics_client.get_template_statistics_for_service',
return_value=copy.deepcopy(stub_template_stats)
)
response = logged_in_client.get(url_for('main.service_dashboard', service_id=SERVICE_ONE_ID))
# mock_get_service_templates.assert_called_once_with(SERVICE_ONE_ID)
+1 -4
View File
@@ -1,13 +1,10 @@
import json
import uuid
from urllib.parse import urlparse, quote, parse_qs
import pytest
from flask import url_for
from bs4 import BeautifulSoup
from app.main.views.jobs import get_time_left, get_status_filters
from tests import notification_json
from app.main.views.jobs import get_time_left
from tests.conftest import SERVICE_ONE_ID, normalize_spaces, mock_get_notifications
from freezegun import freeze_time
-2
View File
@@ -3,8 +3,6 @@ from bs4 import BeautifulSoup
from flask import url_for
from functools import partial
from tests import service_json
letters_urls = [
partial(url_for, 'main.add_service_template', template_type='letter'),
]
@@ -2,13 +2,6 @@ from freezegun import freeze_time
from flask import url_for
import pytest
from app.utils import (
REQUESTED_STATUSES,
FAILURE_STATUSES,
SENDING_STATUSES,
DELIVERED_STATUSES,
)
from notifications_utils.template import LetterImageTemplate
from tests.conftest import mock_get_notification, SERVICE_ONE_ID, normalize_spaces
+6 -13
View File
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import uuid
from unittest.mock import Mock
from io import BytesIO
from os import path
from glob import glob
@@ -25,14 +24,9 @@ from tests.conftest import (
mock_get_service_email_template,
normalize_spaces,
SERVICE_ONE_ID,
mock_get_service,
mock_get_live_service,
multiple_reply_to_email_addresses,
multiple_letter_contact_blocks,
multiple_sms_senders,
no_reply_to_email_addresses,
no_letter_contact_blocks,
no_sms_senders
)
template_types = ['email', 'sms']
@@ -99,7 +93,7 @@ def test_sender_session_is_present_after_selected(
mock_get_service_email_template,
multiple_reply_to_email_addresses
):
response = logged_in_client.post(
logged_in_client.post(
url_for('.set_sender', service_id=service_one['id'], template_id=fake_uuid),
data={'sender': '1234'}
)
@@ -867,7 +861,7 @@ def test_send_test_caches_page_count(
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=99)
response = logged_in_client.get(
logged_in_client.get(
url_for(
'main.send_test',
service_id=service_one['id'],
@@ -1364,8 +1358,6 @@ def test_check_messages_should_revalidate_file_when_uploading_file(
fake_uuid
):
service_id = service_one['id']
mocker.patch(
'app.main.views.send.s3download',
return_value="""
@@ -1374,14 +1366,14 @@ def test_check_messages_should_revalidate_file_when_uploading_file(
+447700900986,,,,
"""
)
data = mock_get_job(service_one['id'], fake_uuid)['data']
data = mock_get_job(SERVICE_ONE_ID, fake_uuid)['data']
with logged_in_client.session_transaction() as session:
session['upload_data'] = {'original_file_name': 'invalid.csv',
'template_id': data['template'],
'notification_count': data['notification_count'],
'valid': True}
response = logged_in_client.post(
url_for('main.start_job', service_id=service_one['id'], upload_id=data['id']),
url_for('main.start_job', service_id=SERVICE_ONE_ID, upload_id=data['id']),
data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
content_type='multipart/form-data',
follow_redirects=True
@@ -1459,7 +1451,8 @@ def test_route_permissions_send_check_notifications(
),
['send_texts', 'send_emails', 'send_letters'],
api_user_active,
service_one)
service_one
)
@pytest.mark.parametrize('route', [
+29 -27
View File
@@ -15,10 +15,8 @@ from tests.conftest import (
platform_admin_user,
normalize_spaces,
no_reply_to_email_addresses,
single_reply_to_email_address,
multiple_reply_to_email_addresses,
multiple_letter_contact_blocks,
no_reply_to_email_addresses,
no_letter_contact_blocks,
get_default_reply_to_email_address,
get_non_default_reply_to_email_address,
@@ -178,14 +176,15 @@ def test_service_settings_show_elided_api_url_if_needed(
fake_uuid,
url,
elided_url,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
service_one['permissions'] = ['sms', 'email', 'inbound_sms']
service_one['inbound_api'] = [fake_uuid]
mocked_get_fn = mocker.patch(
'app.service_api_client.get',
return_value={'data': {'id': fake_uuid, 'url': url}})
return_value={'data': {'id': fake_uuid, 'url': url}}
)
response = logged_in_platform_admin_client.get(
url_for(
@@ -200,6 +199,7 @@ def test_service_settings_show_elided_api_url_if_needed(
api_url = [api_setting[1].text.strip() for api_setting in non_empty_trs
if api_setting[0].text.strip() == 'API endpoint for received text messages'][0]
assert api_url == elided_url
assert mocked_get_fn.called is True
def test_if_cant_send_letters_then_cant_see_letter_contact_block(
@@ -871,7 +871,7 @@ def test_add_reply_to_email_address(
):
fixture(mocker)
data['email_address'] = "test@example.gov.uk"
page = client_request.post(
client_request.post(
'main.service_add_email_reply_to',
service_id=SERVICE_ONE_ID,
_data=data
@@ -899,7 +899,7 @@ def test_add_letter_contact(
):
fixture(mocker)
data['letter_contact_block'] = "1 Example Street"
page = client_request.post(
client_request.post(
'main.service_add_letter_contact',
service_id=SERVICE_ONE_ID,
_data=data
@@ -951,7 +951,7 @@ def test_edit_reply_to_email_address(
):
fixture(mocker)
data['email_address'] = "test@example.gov.uk"
page = client_request.post(
client_request.post(
'main.service_edit_email_reply_to',
service_id=SERVICE_ONE_ID,
reply_to_email_id=fake_uuid,
@@ -983,7 +983,7 @@ def test_edit_letter_contact_block(
):
fixture(mocker)
data['letter_contact_block'] = "1 Example Street"
page = client_request.post(
client_request.post(
'main.service_edit_letter_contact',
service_id=SERVICE_ONE_ID,
letter_contact_id=fake_uuid,
@@ -1105,7 +1105,7 @@ def test_shows_research_mode_indicator(
mock_get_letter_organisations,
single_reply_to_email_address,
single_letter_contact_block,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
service_one['research_mode'] = True
mocker.patch('app.service_api_client.update_service_with_properties', return_value=service_one)
@@ -1124,7 +1124,7 @@ def test_does_not_show_research_mode_indicator(
mock_get_letter_organisations,
single_reply_to_email_address,
single_letter_contact_block,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
response = logged_in_client.get(url_for('main.service_settings', service_id=service_one['id']))
assert response.status_code == 200
@@ -1166,7 +1166,7 @@ def test_set_inbound_api_validation(
def test_cant_set_letter_contact_block_if_service_cant_send_letters(
logged_in_client,
service_one,
method
method,
):
assert 'letter' not in service_one['permissions']
response = getattr(logged_in_client, method)(
@@ -1177,7 +1177,7 @@ def test_cant_set_letter_contact_block_if_service_cant_send_letters(
def test_set_letter_contact_block_prepopulates(
logged_in_client,
service_one
service_one,
):
service_one['permissions'] = ['letter']
service_one['letter_contact_block'] = 'foo bar baz waz'
@@ -1268,7 +1268,7 @@ def test_set_letter_branding_prepopulates(
assert page.select('input[checked]')[0]['value'] == expected_selected
def test_set_letter_contact_block_saves(
def test_set_letter_branding_saves(
logged_in_platform_admin_client,
service_one,
mock_update_service,
@@ -1312,7 +1312,7 @@ def test_should_show_branding(
def test_should_show_organisations(
logged_in_platform_admin_client,
service_one,
mock_get_organisations
mock_get_organisations,
):
response = logged_in_platform_admin_client.get(url_for(
'main.service_set_branding_and_org', service_id=service_one['id']
@@ -1430,7 +1430,7 @@ def test_switch_service_enable_international_sms(
international_sms_permission_expected_in_api_call,
):
mocked_fn = mocker.patch('app.service_api_client.update_service_with_properties', return_value=service_one)
page = client_request.post(
client_request.post(
'main.service_set_international_sms',
service_id=service_one['id'],
_data={
@@ -1485,7 +1485,7 @@ def test_update_inbound_api_and_valid_bearer_token_calls_update_inbound_api_endp
service_one,
mocker,
fake_uuid,
inbound_api_data
inbound_api_data,
):
service_one['permissions'] = ['inbound_sms']
service_one['inbound_api'] = [fake_uuid]
@@ -1515,7 +1515,8 @@ def test_update_inbound_api_and_valid_bearer_token_calls_update_inbound_api_endp
)
assert response.status_code == 302
assert response.location == url_for('main.service_settings', service_id=service_one['id'], _external=True)
assert mocked_post_fn.called
assert mocked_get_fn.called is True
assert mocked_post_fn.called is True
if inbound_api_data['bearer_token'] == dummy_bearer_token:
del inbound_api_data['bearer_token']
@@ -1529,7 +1530,7 @@ def test_save_inbound_api_without_changes_does_not_update_inbound_api(
logged_in_platform_admin_client,
service_one,
mocker,
fake_uuid
fake_uuid,
):
service_one['permissions'] = ['inbound_sms']
service_one['inbound_api'] = [fake_uuid]
@@ -1549,6 +1550,7 @@ def test_save_inbound_api_without_changes_does_not_update_inbound_api(
)
assert response.status_code == 302
assert response.location == url_for('main.service_settings', service_id=service_one['id'], _external=True)
assert mocked_get_fn.called is True
assert mocked_post_fn.called is False
@@ -1556,7 +1558,7 @@ def test_archive_service_after_confirm(
logged_in_platform_admin_client,
service_one,
mocker,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
mocked_fn = mocker.patch('app.service_api_client.post', return_value=service_one)
@@ -1574,7 +1576,7 @@ def test_archive_service_prompts_user(
single_reply_to_email_address,
single_letter_contact_block,
mock_get_letter_organisations,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
mocked_fn = mocker.patch('app.service_api_client.post')
@@ -1592,7 +1594,7 @@ def test_cant_archive_inactive_service(
single_reply_to_email_address,
single_letter_contact_block,
mock_get_letter_organisations,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
service_one['active'] = False
@@ -1607,7 +1609,7 @@ def test_suspend_service_after_confirm(
logged_in_platform_admin_client,
service_one,
mocker,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
mocked_fn = mocker.patch('app.service_api_client.post', return_value=service_one)
@@ -1625,7 +1627,7 @@ def test_suspend_service_prompts_user(
single_reply_to_email_address,
single_letter_contact_block,
mock_get_letter_organisations,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
mocked_fn = mocker.patch('app.service_api_client.post')
@@ -1644,7 +1646,7 @@ def test_cant_suspend_inactive_service(
single_reply_to_email_address,
single_letter_contact_block,
mock_get_letter_organisations,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
service_one['active'] = False
@@ -1661,7 +1663,7 @@ def test_resume_service_after_confirm(
single_reply_to_email_address,
single_letter_contact_block,
mocker,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
service_one['active'] = False
mocked_fn = mocker.patch('app.service_api_client.post', return_value=service_one)
@@ -1680,7 +1682,7 @@ def test_resume_service_prompts_user(
single_letter_contact_block,
mocker,
mock_get_letter_organisations,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
service_one['active'] = False
mocked_fn = mocker.patch('app.service_api_client.post')
@@ -1700,7 +1702,7 @@ def test_cant_resume_active_service(
single_reply_to_email_address,
single_letter_contact_block,
mock_get_letter_organisations,
mock_get_inbound_number_for_service
mock_get_inbound_number_for_service,
):
response = logged_in_platform_admin_client.get(url_for('main.service_settings', service_id=service_one['id']))
-2
View File
@@ -1,6 +1,5 @@
from datetime import datetime
from unittest.mock import Mock, ANY
import uuid
import pytest
from bs4 import BeautifulSoup
@@ -16,7 +15,6 @@ from tests.conftest import (
SERVICE_ONE_ID,
active_user_with_permissions,
platform_admin_user,
mock_get_user,
)
from tests import validate_route_permission, template_json, single_notification_json
@@ -76,7 +76,7 @@ def test_get_api_notifications_changes_letter_statuses(mocker):
notis = notification_json(service_id=service_id, rows=0)
notis['notifications'] = [sms_notification, email_notification, letter_notification]
mock_post = mocker.patch('app.notify_client.notification_api_client.NotificationApiClient.get', return_value=notis)
mocker.patch('app.notify_client.notification_api_client.NotificationApiClient.get', return_value=notis)
ret = NotificationApiClient().get_api_notifications_for_service(service_id)