diff --git a/.ahoy.yml b/.ahoy.yml index 55010b89..aab8def3 100644 --- a/.ahoy.yml +++ b/.ahoy.yml @@ -127,7 +127,7 @@ commands: ahoy cli "behave ${*:-/app/test/features}" || \ [ "${ALLOW_BDD_FAIL:-0}" -eq 1 ] ahoy stop-mailmock - ahoy stop-ckan-job-worker + ahoy stop-ckan-job-worker start-mailmock: @@ -147,8 +147,9 @@ commands: cmd: | ahoy title 'Starting CKAN background job worker' ahoy cli "cd /usr/lib/ckan/default/src/ckan && \ - paster jobs clear --config=/app/ckan/default/production.ini && \ - paster jobs worker default --config=/app/ckan/default/production.ini" + export CKAN_INI=/app/ckan/default/production.ini && + /app/scripts/ckan_cli jobs clear && \ + /app/scripts/ckan_cli jobs worker default" stop-ckan-job-worker: usage: Stops CKAN background job worker diff --git a/.docker/Dockerfile.ckan b/.docker/Dockerfile.ckan index e95d8f7a..5324f7e3 100644 --- a/.docker/Dockerfile.ckan +++ b/.docker/Dockerfile.ckan @@ -30,7 +30,8 @@ RUN fix-permissions /app/ckan \ && chmod +x /app/scripts/create-test-data.sh \ && chmod +x /app/scripts/init.sh \ && chmod +x /app/scripts/init-ext.sh \ - && chmod +x /app/scripts/serve.sh + && chmod +x /app/scripts/serve.sh \ + && chmod +x /app/scripts/ckan_cli # Add current extension and files. COPY ckanext /app/ckanext diff --git a/.docker/scripts/ckan_cli b/.docker/scripts/ckan_cli new file mode 100644 index 00000000..88526ff9 --- /dev/null +++ b/.docker/scripts/ckan_cli @@ -0,0 +1,68 @@ +#!/bin/sh + +# Call either 'ckan' (from CKAN >= 2.9) or 'paster' (from CKAN <= 2.8) +# with appropriate syntax, depending on what is present on the system. +# This is intended to smooth the upgrade process from 2.8 to 2.9. +# Eg: +# ckan_cli jobs list +# could become either: +# paster --plugin=ckan jobs list -c /etc/ckan/default/production.ini +# or: +# ckan -c /etc/ckan/default/production.ini jobs list + +# This script is aware of the VIRTUAL_ENV environment variable, and will +# attempt to respect it with similar behaviour to commands like 'pip'. +# Eg placing this script in a virtualenv 'bin' directory will cause it +# to call the 'ckan' or 'paster' command in that directory, while +# placing this script elsewhere will cause it to rely on the VIRTUAL_ENV +# variable, or if that is not set, the system PATH. + +# Since the positioning of the CKAN configuration file is central to the +# differences between 'paster' and 'ckan', this script needs to be aware +# of the config file location. It will use the CKAN_INI environment +# variable if it exists, or default to /etc/ckan/default/production.ini. + +# If 'paster' is being used, the default plugin is 'ckan'. A different +# plugin can be specified by setting the PASTER_PLUGIN environment +# variable. This variable is irrelevant if using the 'ckan' command. + +CKAN_INI="${CKAN_INI:-/etc/ckan/default/production.ini}" +PASTER_PLUGIN="${PASTER_PLUGIN:-ckan}" +# First, look for a command alongside this file +ENV_DIR=$(dirname "$0") +if [ -f "$ENV_DIR/ckan" ]; then + COMMAND=ckan +elif [ -f "$ENV_DIR/paster" ]; then + COMMAND=paster +elif [ "$VIRTUAL_ENV" != "" ]; then + # If command not found alongside this file, check the virtualenv + ENV_DIR="$VIRTUAL_ENV/bin" + if [ -f "$ENV_DIR/ckan" ]; then + COMMAND=ckan + elif [ -f "$ENV_DIR/paster" ]; then + COMMAND=paster + fi +else + # if no virtualenv is active, try the system path + if (which ckan > /dev/null 2>&1); then + ENV_DIR=$(dirname $(which ckan)) + COMMAND=ckan + elif (which paster > /dev/null 2>&1); then + ENV_DIR=$(dirname $(which paster)) + COMMAND=paster + else + echo "Unable to locate 'ckan' or 'paster' command" >&2 + exit 1 + fi +fi + +if [ "$COMMAND" = "ckan" ]; then + echo "Using 'ckan' command from $ENV_DIR..." >&2 + exec $ENV_DIR/ckan -c ${CKAN_INI} "$@" +elif [ "$COMMAND" = "paster" ]; then + echo "Using 'paster' command from $ENV_DIR..." >&2 + exec $ENV_DIR/paster --plugin=$PASTER_PLUGIN "$@" -c ${CKAN_INI} +else + echo "Unable to locate 'ckan' or 'paster' command in $ENV_DIR" >&2 + exit 1 +fi diff --git a/.docker/scripts/create-test-data.sh b/.docker/scripts/create-test-data.sh index f707be2c..504f9ac4 100644 --- a/.docker/scripts/create-test-data.sh +++ b/.docker/scripts/create-test-data.sh @@ -6,17 +6,16 @@ set -e CKAN_ACTION_URL=http://ckan:3000/api/action -CKAN_INI_FILE=/app/ckan/default/production.ini +export CKAN_INI=/app/ckan/default/production.ini -. /app/ckan/default/bin/activate \ - && cd /app/ckan/default/src/ckan +. /app/ckan/default/bin/activate # We know the "admin" sysadmin account exists, so we'll use her API KEY to create further data -API_KEY=$(paster --plugin=ckan user admin -c ${CKAN_INI_FILE} | tr -d '\n' | sed -r 's/^(.*)apikey=(\S*)(.*)/\2/') +API_KEY=$(/app/scripts/ckan_cli user admin | tr -d '\n' | sed -r 's/^(.*)apikey=(\S*)(.*)/\2/') -# # +# # ## -# BEGIN: Add sysadmin config values. +# BEGIN: Add sysadmin config values. # This needs to be done before closing datarequests as they require the below config values # echo "Adding ckan.datarequests.closing_circumstances:" @@ -37,10 +36,10 @@ TEST_ORG_TITLE="Test" echo "Creating test users for ${TEST_ORG_TITLE} Organisation:" -paster --plugin=ckan user add ckan_user email=ckan_user@localhost password=password -c ${CKAN_INI_FILE} -paster --plugin=ckan user add test_org_admin email=test_org_admin@localhost password=password -c ${CKAN_INI_FILE} -paster --plugin=ckan user add test_org_editor email=test_org_editor@localhost password=password -c ${CKAN_INI_FILE} -paster --plugin=ckan user add test_org_member email=test_org_member@localhost password=password -c ${CKAN_INI_FILE} +/app/scripts/ckan_cli user add ckan_user email=ckan_user@localhost password=password +/app/scripts/ckan_cli user add test_org_admin email=test_org_admin@localhost password=password +/app/scripts/ckan_cli user add test_org_editor email=test_org_editor@localhost password=password +/app/scripts/ckan_cli user add test_org_member email=test_org_member@localhost password=password echo "Creating ${TEST_ORG_TITLE} Organisation:" @@ -78,9 +77,9 @@ DR_ORG_TITLE="Open Data Administration (data requests)" echo "Creating test users for ${DR_ORG_TITLE} Organisation:" -paster --plugin=ckan user add dr_admin email=dr_admin@localhost password=password -c ${CKAN_INI_FILE} -paster --plugin=ckan user add dr_editor email=dr_editor@localhost password=password -c ${CKAN_INI_FILE} -paster --plugin=ckan user add dr_member email=dr_member@localhost password=password -c ${CKAN_INI_FILE} +/app/scripts/ckan_cli user add dr_admin email=dr_admin@localhost password=password +/app/scripts/ckan_cli user add dr_editor email=dr_editor@localhost password=password +/app/scripts/ckan_cli user add dr_member email=dr_member@localhost password=password echo "Creating ${DR_ORG_TITLE} Organisation:" @@ -138,8 +137,8 @@ curl -L -s --header "Authorization: ${API_KEY}" \ # END. # -# Use CKAN's built-in paster command for creating some test datasets... -paster create-test-data -c ${CKAN_INI_FILE} +# Use CKAN's built-in commands for creating some test datasets... +/app/scripts/ckan_cli create-test-data # Datasets need to be assigned to an organisation diff --git a/.docker/scripts/init-ext.sh b/.docker/scripts/init-ext.sh index 8354ddfe..73ebd4ad 100755 --- a/.docker/scripts/init-ext.sh +++ b/.docker/scripts/init-ext.sh @@ -9,8 +9,9 @@ set -e pip install -r "/app/requirements.txt" pip install -r "/app/requirements-dev.txt" python setup.py develop +installed_name=$(grep '^\s*name=' setup.py |sed "s|[^']*'\([-a-zA-Z0-9]*\)'.*|\1|") # Validate that the extension was installed correctly. -if ! pip list | grep ckanext-datarequests > /dev/null; then echo "Unable to find the extension in the list"; exit 1; fi +if ! pip list | grep "$installed_name" > /dev/null; then echo "Unable to find the extension in the list"; exit 1; fi deactivate diff --git a/.docker/scripts/init.sh b/.docker/scripts/init.sh index 24b0ca91..2dca5136 100755 --- a/.docker/scripts/init.sh +++ b/.docker/scripts/init.sh @@ -7,25 +7,25 @@ set -e CKAN_USER_NAME="${CKAN_USER_NAME:-admin}" CKAN_USER_PASSWORD="${CKAN_USER_PASSWORD:-password}" CKAN_USER_EMAIL="${CKAN_USER_EMAIL:-admin@localhost}" +export CKAN_INI=/app/ckan/default/production.ini -. /app/ckan/default/bin/activate \ - && cd /app/ckan/default/src/ckan \ - && paster db clean -c /app/ckan/default/production.ini \ - && paster db init -c /app/ckan/default/production.ini \ - && paster --plugin=ckan user add "${CKAN_USER_NAME}" email="${CKAN_USER_EMAIL}" password="${CKAN_USER_PASSWORD}" -c /app/ckan/default/production.ini \ - && paster --plugin=ckan sysadmin add "${CKAN_USER_NAME}" -c /app/ckan/default/production.ini +. /app/ckan/default/bin/activate +/app/scripts/ckan_cli db clean +/app/scripts/ckan_cli db init +/app/scripts/ckan_cli user add "${CKAN_USER_NAME}" email="${CKAN_USER_EMAIL}" password="${CKAN_USER_PASSWORD}" +/app/scripts/ckan_cli sysadmin add "${CKAN_USER_NAME}" # Initialise the Comments database tables -paster --plugin=ckanext-ytp-comments initdb --config=/app/ckan/default/production.ini +PASTER_PLUGIN=ckanext-ytp-comments /app/scripts/ckan_cli initdb # Initialise the archiver database tables -paster --plugin=ckanext-archiver archiver init --config=/app/ckan/default/production.ini +PASTER_PLUGIN=ckanext-archiver /app/scripts/ckan_cli archiver init # Initialise the reporting database tables -paster --plugin=ckanext-report report initdb --config=/app/ckan/default/production.ini +PASTER_PLUGIN=ckanext-report /app/scripts/ckan_cli report initdb # Initialise the QA database tables -paster --plugin=ckanext-qa qa init --config=/app/ckan/default/production.ini +PASTER_PLUGIN=ckanext-qa /app/scripts/ckan_cli qa init # Create some base test data . /app/scripts/create-test-data.sh diff --git a/.flake8 b/.flake8 index f443751e..09a146e3 100644 --- a/.flake8 +++ b/.flake8 @@ -15,5 +15,7 @@ max-complexity = 10 # List ignore rules one per line. ignore = + E241 + E266 E501 C901 diff --git a/ckanext/datarequests/actions.py b/ckanext/datarequests/actions.py index e727ae45..bf74d402 100644 --- a/ckanext/datarequests/actions.py +++ b/ckanext/datarequests/actions.py @@ -18,16 +18,14 @@ # along with CKAN Data Requests Extension. If not, see . -import ckan.lib.base as base -import ckan.model as model -import ckan.plugins as plugins import constants import datetime import cgi import db import logging import validator -import ckan.lib.mailer as mailer +from ckan import model, plugins +from ckan.lib import base, mailer from pylons import config @@ -201,7 +199,7 @@ def create_datarequest(context, data_dict): :type organization_id: string :returns: A dict with the data request (id, user_id, title, description, - organization_id, open_time, accepted_dataset, close_time, closed, + organization_id, open_time, accepted_dataset, close_time, closed, followers) :rtype: dict ''' @@ -230,7 +228,7 @@ def create_datarequest(context, data_dict): datarequest_dict = _dictize_datarequest(data_req) if datarequest_dict['organization']: - users = set([user['id'] for user in datarequest_dict['organization']['users']]) + users = {user['id'] for user in datarequest_dict['organization']['users']} users.discard(context['auth_user_obj'].id) _send_mail(users, 'new_datarequest', datarequest_dict) @@ -250,7 +248,7 @@ def show_datarequest(context, data_dict): :type id: string :returns: A dict with the data request (id, user_id, title, description, - organization_id, open_time, accepted_dataset, close_time, closed, + organization_id, open_time, accepted_dataset, close_time, closed, followers) :rtype: dict ''' @@ -302,7 +300,7 @@ def update_datarequest(context, data_dict): :type organization_id: string :returns: A dict with the data request (id, user_id, title, description, - organization_id, open_time, accepted_dataset, close_time, closed, + organization_id, open_time, accepted_dataset, close_time, closed, followers) :rtype: dict ''' @@ -455,7 +453,7 @@ def list_datarequests(context, data_dict): 'display_name': organization.get('display_name'), 'count': no_processed_organization_facet[organization_id] }) - except: + except Exception: pass state_facet = [] @@ -493,7 +491,7 @@ def delete_datarequest(context, data_dict): :type id: string :returns: A dict with the data request (id, user_id, title, description, - organization_id, open_time, accepted_dataset, close_time, closed, + organization_id, open_time, accepted_dataset, close_time, closed, followers) :rtype: dict ''' @@ -538,7 +536,7 @@ def close_datarequest(context, data_dict): :type accepted_dataset_id: string :returns: A dict with the data request (id, user_id, title, description, - organization_id, open_time, accepted_dataset, close_time, closed, + organization_id, open_time, accepted_dataset, close_time, closed, followers) :rtype: dict @@ -821,11 +819,11 @@ def delete_datarequest_comment(context, data_dict): def follow_datarequest(context, data_dict): ''' - Action to follow a data request. Access rights will be cheked before + Action to follow a data request. Access rights will be cheked before following a datarequest and a NotAuthorized exception will be risen if the user is not allowed to follow the given datarequest. ValidationError will be risen if the datarequest ID is not included or if the user is already - following the datarequest. ObjectNotFound will be risen if the given + following the datarequest. ObjectNotFound will be risen if the given datarequest does not exist. :param id: The ID of the datarequest to be followed @@ -873,11 +871,11 @@ def follow_datarequest(context, data_dict): def unfollow_datarequest(context, data_dict): ''' - Action to unfollow a data request. Access rights will be cheked before + Action to unfollow a data request. Access rights will be cheked before unfollowing a datarequest and a NotAuthorized exception will be risen if the user is not allowed to unfollow the given datarequest. ValidationError - will be risen if the datarequest ID is not included in the request. - ObjectNotFound will be risen if the user is not following the given + will be risen if the datarequest ID is not included in the request. + ObjectNotFound will be risen if the user is not following the given datarequest. :param id: The ID of the datarequest to be unfollowed diff --git a/ckanext/datarequests/controllers/ui_controller.py b/ckanext/datarequests/controllers/ui_controller.py index d68f8f7b..28b88ef2 100644 --- a/ckanext/datarequests/controllers/ui_controller.py +++ b/ckanext/datarequests/controllers/ui_controller.py @@ -19,16 +19,16 @@ import logging -import ckan.lib.base as base -import ckan.model as model -import ckan.plugins as plugins -import ckan.lib.helpers as helpers -import ckanext.datarequests.constants as constants import functools import re +import six +from six.moves.urllib.parse import urlencode + +from ckan import model, plugins from ckan.common import request -from urllib import urlencode +from ckan.lib import base, helpers +from ckanext.datarequests import constants _link = re.compile(r'(?:(https?://)|(www\.))(\S+\b/?)([!"#$%&\'()*+,\-./:;<=>?@[\\\]^_`{|}~]*)(\s|$)', re.I) @@ -48,7 +48,7 @@ def _get_errors_summary(errors): def _encode_params(params): - return [(k, v.encode('utf-8') if isinstance(v, basestring) else str(v)) + return [(k, v.encode('utf-8') if isinstance(v, six.string_types) else str(v)) for k, v in params] @@ -84,7 +84,7 @@ def _get_context(self): def _show_index(self, user_id, organization_id, include_organization_facet, url_func, file_to_render): def pager_url(state=None, sort=None, q=None, page=None): - params = list() + params = [] if q: params.append(('q', q)) @@ -220,7 +220,7 @@ def show(self, id): context_ignore_auth['ignore_auth'] = True return tk.render('datarequests/show.html') - except tk.ObjectNotFound as e: + except tk.ObjectNotFound: tk.abort(404, tk._('Data Request %s not found') % id) except tk.NotAuthorized as e: log.warn(e) @@ -286,9 +286,11 @@ def close(self, id): # Basic intialization c.datarequest = {} - def _return_page(errors={}, errors_summary={}): - # Get datasets (if the data req belongs to an organization, only the one that - # belongs to the organization are shown) + def _return_page(errors=None, errors_summary=None): + errors = errors or {} + errors_summary = errors_summary or {} + # Get datasets (if the data req belongs to an organization, + # only the ones that belong to the organization are shown) organization_id = c.datarequest.get('organization_id', '') if organization_id: base_datasets = tk.get_action('organization_show')({'ignore_auth': True}, {'id': organization_id, 'include_datasets': True})['packages'] diff --git a/ckanext/datarequests/db.py b/ckanext/datarequests/db.py index 731be6f1..e8306290 100644 --- a/ckanext/datarequests/db.py +++ b/ckanext/datarequests/db.py @@ -187,7 +187,7 @@ def get_datarequest_followers_number(cls, **kw): def update_db(model): - ''' + ''' A place to make any datarequest table updates via SQL commands This is required because adding new columns to sqlalchemy metadata will not get created if the table already exists ''' diff --git a/ckanext/datarequests/helpers.py b/ckanext/datarequests/helpers.py index e547d621..845e2660 100644 --- a/ckanext/datarequests/helpers.py +++ b/ckanext/datarequests/helpers.py @@ -17,11 +17,11 @@ # You should have received a copy of the GNU Affero General Public License # along with CKAN Data Requests Extension. If not, see . -import ckan.model as model -import ckan.plugins.toolkit as tk import db +from ckan import model from ckan.common import c +import ckan.plugins.toolkit as tk def get_comments_number(datarequest_id): diff --git a/ckanext/datarequests/plugin.py b/ckanext/datarequests/plugin.py index b3b631dd..05232b5e 100644 --- a/ckanext/datarequests/plugin.py +++ b/ckanext/datarequests/plugin.py @@ -25,6 +25,7 @@ import constants import helpers import os +import six import sys from functools import partial @@ -144,7 +145,7 @@ def update_config_schema(self, schema): ignore_missing = tk.get_validator('ignore_missing') schema.update({ # This is a custom configuration option - 'ckan.datarequests.closing_circumstances': [ignore_missing, unicode], + 'ckan.datarequests.closing_circumstances': [ignore_missing, six.text_type], }) return schema @@ -156,64 +157,64 @@ def before_map(self, m): # Data Requests index m.connect('datarequests_index', "/%s" % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='index', conditions=dict(method=['GET'])) + action='index', conditions={'method': ['GET']}) # Create a Data Request m.connect('/%s/new' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='new', conditions=dict(method=['GET', 'POST'])) + action='new', conditions={'method': ['GET', 'POST']}) # Show a Data Request m.connect('show_datarequest', '/%s/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='show', conditions=dict(method=['GET']), ckan_icon=get_question_icon()) + action='show', conditions={'method': ['GET']}, ckan_icon=get_question_icon()) # Update a Data Request m.connect('/%s/edit/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='update', conditions=dict(method=['GET', 'POST'])) + action='update', conditions={'method': ['GET', 'POST']}) # Delete a Data Request m.connect('/%s/delete/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='delete', conditions=dict(method=['POST'])) + action='delete', conditions={'method': ['POST']}) # Close a Data Request m.connect('/%s/close/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='close', conditions=dict(method=['GET', 'POST'])) + action='close', conditions={'method': ['GET', 'POST']}) # Data Request that belongs to an organization m.connect('organization_datarequests', '/organization/%s/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='organization_datarequests', conditions=dict(method=['GET']), + action='organization_datarequests', conditions={'method': ['GET']}, ckan_icon=get_question_icon()) # Data Request that belongs to an user m.connect('user_datarequests', '/user/%s/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='user_datarequests', conditions=dict(method=['GET']), + action='user_datarequests', conditions={'method': ['GET']}, ckan_icon=get_question_icon()) # Follow & Unfollow m.connect('/%s/follow/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='follow', conditions=dict(method=['POST'])) + action='follow', conditions={'method': ['POST']}) m.connect('/%s/unfollow/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='unfollow', conditions=dict(method=['POST'])) + action='unfollow', conditions={'method': ['POST']}) if self.comments_enabled: # Comment, update and view comments (of) a Data Request m.connect('comment_datarequest', '/%s/comment/{id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='comment', conditions=dict(method=['GET', 'POST']), ckan_icon='comment') + action='comment', conditions={'method': ['GET', 'POST']}, ckan_icon='comment') # Delete data request m.connect('/%s/comment/{datarequest_id}/delete/{comment_id}' % constants.DATAREQUESTS_MAIN_PATH, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='delete_comment', conditions=dict(method=['GET', 'POST'])) + action='delete_comment', conditions={'method': ['GET', 'POST']}) return m diff --git a/ckanext/datarequests/tests/test_actions.py b/ckanext/datarequests/tests/test_actions.py index 486cb567..e4af8808 100644 --- a/ckanext/datarequests/tests/test_actions.py +++ b/ckanext/datarequests/tests/test_actions.py @@ -17,14 +17,13 @@ # You should have received a copy of the GNU Affero General Public License # along with CKAN Data Requests Extension. If not, see . -import ckanext.datarequests.actions as actions -import ckanext.datarequests.constants as constants +from ckanext.datarequests import actions, constants import datetime import test_actions_data as test_data import unittest from mock import MagicMock, patch -from nose_parameterized import parameterized +from parameterized import parameterized class ActionsTest(unittest.TestCase): @@ -95,7 +94,6 @@ def _check_basic_response(self, datarequest, response, user, organization=None, else: self.assertIsNone(response['close_time']) - ###################################################################### ################################# AUX ################################ ###################################################################### @@ -149,7 +147,6 @@ def _test_comment_not_found(self, function, action, request_data): actions.tk.check_access.assert_called_once_with(action, self.context, request_data) actions.db.Comment.get.assert_called_once_with(id=request_data['id']) - ###################################################################### ######################### GET INVOLVED USERS ######################### ###################################################################### @@ -175,7 +172,7 @@ def test_get_involved_users_no_org_and_current_user_must_be_discarded(self, list result = actions._get_datarequest_involved_users(self.context, datarequest) - self.assertEquals(set(['user-2', 'user-3']), result) + self.assertEquals({'user-2', 'user-3'}, result) actions.db.DataRequestFollower.get.assert_called_once_with(datarequest_id=datarequest_id) list_comments_mock.assert_called_once_with({'ignore_auth': True, 'model': self.context['model']}, {'datarequest_id': datarequest_id}) @@ -201,7 +198,7 @@ def test_get_involved_users_no_org_and_current_user_must_not_be_discarded(self, result = actions._get_datarequest_involved_users(self.context, datarequest) - self.assertEquals(set(['user-1', 'user-2', 'user-3']), result) + self.assertEquals({'user-1', 'user-2', 'user-3'}, result) actions.db.DataRequestFollower.get.assert_called_once_with(datarequest_id=datarequest_id) list_comments_mock.assert_called_once_with({'ignore_auth': True, 'model': self.context['model']}, {'datarequest_id': datarequest_id}) @@ -227,12 +224,11 @@ def test_get_involved_users_org(self, list_comments_mock): result = actions._get_datarequest_involved_users(self.context, datarequest) - self.assertEquals(set(['user-1', 'user-2', 'user-3', 'user-4']), result) + self.assertEquals({'user-1', 'user-2', 'user-3', 'user-4'}, result) actions.db.DataRequestFollower.get.assert_called_once_with(datarequest_id=datarequest_id) list_comments_mock.assert_called_once_with({'ignore_auth': True, 'model': self.context['model']}, {'datarequest_id': datarequest_id}) - ###################################################################### ############################# SEND MAIL ############################## ###################################################################### @@ -258,7 +254,7 @@ def test_send_mail_two_users(self, model_mock, base_mock, mailer_mock, config_mo actions._send_mail(users, action_type, datarequest) - for i, user in enumerate(users): + for i, _ in enumerate(users): extra_args = { 'datarequest': datarequest, 'user': get_users_side_effect[i], @@ -270,7 +266,6 @@ def test_send_mail_two_users(self, model_mock, base_mock, mailer_mock, config_mo mailer_mock.mail_user.assert_any_call(get_users_side_effect[i], subject, body) - @patch('ckanext.datarequests.actions.config') @patch('ckanext.datarequests.actions.mailer') @patch('ckanext.datarequests.actions.base') @@ -302,7 +297,6 @@ def test_send_mail_exception_no_risen(self, model_mock, base_mock, mailer_mock, mailer_mock.mail_user.assert_any_call(user, subject, body) - ###################################################################### ################################# NEW ################################ ###################################################################### @@ -364,7 +358,7 @@ def test_create_datarequest_valid(self, send_mail_mock): self.context['session'].add.assert_called_once_with(datarequest) self.context['session'].commit.assert_called_once() - send_mail_mock.assert_called_once_with(set(['user_1', 'user_2']), 'new_datarequest', result) + send_mail_mock.assert_called_once_with({'user_1', 'user_2'}, 'new_datarequest', result) # Check the object stored in the database self.assertEquals(self.context['auth_user_obj'].id, datarequest.user_id) @@ -376,7 +370,6 @@ def test_create_datarequest_valid(self, send_mail_mock): # Check the returned object self._check_basic_response(datarequest, result, default_user, default_org, default_pkg) - ###################################################################### ################################ SHOW ################################ ###################################################################### @@ -439,7 +432,6 @@ def test_show_datarequest_found_closed(self, organization_id, accepted_dataset_i self._test_show_datarequest_found(datarequest, org_checked, pkg_checked) - ###################################################################### ############################### UPDATE ############################### ###################################################################### @@ -511,7 +503,6 @@ def test_update_datarequest(self, title_checked, organization_id=None, accepted_ pkg = default_pkg if accepted_dataset_id else None self._check_basic_response(datarequest, result, default_user, org, pkg) - ###################################################################### ################################ LIST ################################ ###################################################################### @@ -539,13 +530,11 @@ def test_list_datarequests_not_authorized(self): (test_data.list_datarequests_test_case_17,) ]) def test_list_datarequests(self, test_case): - content = test_case['content'] expected_ddbb_params = test_case['expected_ddbb_params'] ddbb_response = test_case['ddbb_response'] expected_response = test_case['expected_response'] _organization_show = test_case['organization_show_func'] - _user_show = test_case.get('user_show_func', None) # Set the mocks actions.db.DataRequest.get_ordered_by_date.return_value = ddbb_response @@ -576,7 +565,7 @@ def test_list_datarequests(self, test_case): organization_show.assert_any_call({'ignore_auth': True}, {'id': content['organization_id']}) expected_organization_show_calls += 1 - # The reamining ones to include the display name into the facets + # The remaining ones to include the display name into the facets if 'organization' in expected_response['facets']: expected_organization_show_calls += len(expected_response['facets']['organization']['items']) for organization_facet in expected_response['facets']['organization']['items']: @@ -620,7 +609,6 @@ def test_list_datarequests(self, test_case): for item in items: self.assertIn(item, response['facets'][facet]['items']) - ###################################################################### ############################### DELETE ############################### ###################################################################### @@ -666,7 +654,6 @@ def test_delete_datarequest(self, organization_id, accepted_dataset_id): pkg = default_pkg if accepted_dataset_id else None self._check_basic_response(datarequest, result, default_user, org, pkg) - ###################################################################### ################################ CLOSE ############################### ###################################################################### @@ -704,7 +691,7 @@ def test_close_datarequest(self, data, expected_accepted_ds, organization_id): send_mail_patch = patch('ckanext.datarequests.actions._send_mail') send_mail_mock = send_mail_patch.start() self.addCleanup(send_mail_patch.stop) - + get_datarequest_involved_users_patch = patch('ckanext.datarequests.actions._get_datarequest_involved_users') get_datarequest_involved_users_mock = get_datarequest_involved_users_patch.start() self.addCleanup(get_datarequest_involved_users_patch.stop) @@ -740,7 +727,6 @@ def test_close_datarequest(self, data, expected_accepted_ds, organization_id): send_mail_mock.assert_called_once_with(get_datarequest_involved_users_mock.return_value, 'close_datarequest', result) get_datarequest_involved_users_mock.assert_called_once_with(self.context, result) - ###################################################################### ############################### COMMENT ############################## ###################################################################### @@ -751,7 +737,7 @@ def test_comment_not_authorized(self): def test_comment_no_id(self): self._test_no_id(actions.comment_datarequest) - def test_comment_invalid(self, function=actions.comment_datarequest, check_access=constants.COMMENT_DATAREQUEST, + def test_comment_invalid(self, function=actions.comment_datarequest, check_access=constants.COMMENT_DATAREQUEST, request_data=test_data.comment_request_data): ''' This function is also used to check invalid content when a comment is updated @@ -810,7 +796,6 @@ def test_comment(self, get_datarequest_involved_users_mock, send_mail_mock): send_mail_mock.assert_called_once_with(get_datarequest_involved_users_mock.return_value, 'new_comment', datarequest_dict) get_datarequest_involved_users_mock.assert_called_once_with(self.context, datarequest_dict) - ###################################################################### ############################ SHOW COMMENT ############################ ###################################################################### @@ -839,7 +824,6 @@ def test_comment_show(self): # Check that the response is OK self._check_comment(comment, result, default_user) - ###################################################################### ############################ LIST COMMENTS ########################### ###################################################################### @@ -858,9 +842,7 @@ def test_comment_list_no_id(self): ]) def test_comment_list(self, sort=None, desc=False): # Configure mock - comments = [] - for i in range(0, 5): - comments.append(test_data._generate_basic_comment()) + comments = [test_data._generate_basic_comment() for _ in range(0, 5)] actions.db.Comment.get_ordered_by_date.return_value = comments @@ -885,7 +867,6 @@ def test_comment_list(self, sort=None, desc=False): for i in range(0, len(results)): self._check_comment(comments[i], results[i], default_user) - ###################################################################### ########################### UPDATE COMMENT ########################### ###################################################################### @@ -939,7 +920,6 @@ def test_comment_update(self): # Check the result self._check_comment(comment, result, default_user) - ###################################################################### ########################### DELETE COMMENT ########################### ###################################################################### @@ -1031,8 +1011,8 @@ def test_follow(self): def test_unfollow_not_authorized(self): self._test_not_authorized(actions.unfollow_datarequest, constants.UNFOLLOW_DATAREQUEST, test_data.follow_data_request_data) - def test_follow_no_id(self): - self._test_no_id(actions.follow_datarequest) + def test_unfollow_no_id(self): + self._test_no_id(actions.unfollow_datarequest) def test_unfollow_not_following(self): # Configure the mock @@ -1061,4 +1041,3 @@ def test_unfollow(self): self.context['session'].commit.assert_called_once() self.assertTrue(result) - diff --git a/ckanext/datarequests/tests/test_actions_data.py b/ckanext/datarequests/tests/test_actions_data.py index 6012a63b..490a6dd9 100644 --- a/ckanext/datarequests/tests/test_actions_data.py +++ b/ckanext/datarequests/tests/test_actions_data.py @@ -31,6 +31,7 @@ ############################## FUNCTIONS ############################# ###################################################################### + def dictice_ddbb_response(datarequest): return { 'id': datarequest.id, @@ -62,23 +63,20 @@ def _generate_basic_ddbb_response(number, organizations=None, closed=None): an exception will be risen ''' if not organizations: - organizations = list() - for _ in range(number): - organizations.append(None) + organizations = [None for _ in range(number)] if not closed: - closed = list() - for _ in range(number): - closed.append(False) + closed = [False for _ in range(number)] # Check that length of the arrays is correct assert number == len(organizations) assert number == len(closed) - response = list() - for n in range(number): - response.append(_generate_basic_datarequest(organization_id=organizations[n], - closed=closed[n])) + response = [ + _generate_basic_datarequest( + organization_id=organizations[n], + closed=closed[n]) for n in range(number) + ] return response diff --git a/ckanext/datarequests/tests/test_auth.py b/ckanext/datarequests/tests/test_auth.py index d3341039..1bc27a00 100644 --- a/ckanext/datarequests/tests/test_auth.py +++ b/ckanext/datarequests/tests/test_auth.py @@ -18,12 +18,11 @@ # along with CKAN Data Requests Extension. If not, see . -import ckanext.datarequests.constants as constants -import ckanext.datarequests.auth as auth +from ckanext.datarequests import auth, constants import unittest from mock import MagicMock -from nose_parameterized import parameterized +from parameterized import parameterized # Needed for the test context = { @@ -46,9 +45,10 @@ } request_follow = { - 'datarequest_id': 'example_uuid_v4', + 'datarequest_id': 'example_uuid_v4', } + class AuthTest(unittest.TestCase): def setUp(self): diff --git a/ckanext/datarequests/tests/test_db.py b/ckanext/datarequests/tests/test_db.py index 18b53e42..53c427af 100644 --- a/ckanext/datarequests/tests/test_db.py +++ b/ckanext/datarequests/tests/test_db.py @@ -18,10 +18,10 @@ # along with CKAN Data Requests Extension. If not, see . import unittest -import ckanext.datarequests.db as db +from ckanext.datarequests import db from mock import MagicMock -from nose_parameterized import parameterized +from parameterized import parameterized class DBTest(unittest.TestCase): @@ -115,8 +115,8 @@ def _test_get_ordered_by_date(self, table, time_column, params): title_column_value = MagicMock() description_column_value = MagicMock() setattr(table, time_column, time_column_value) - setattr(table, 'title', title_column_value) - setattr(table, 'description', description_column_value) + table.title = title_column_value + table.description = description_column_value # Call the method result = table.get_ordered_by_date(**params) @@ -355,4 +355,3 @@ def test_get_datarequest_followers_number(self): query.filter_by.assert_called_once_with(**params) model.Session.query.assert_called_once_with(count) db.func.count.assert_called_once_with(db.DataRequestFollower.id) - diff --git a/ckanext/datarequests/tests/test_helpers.py b/ckanext/datarequests/tests/test_helpers.py index 147facba..e0e54651 100644 --- a/ckanext/datarequests/tests/test_helpers.py +++ b/ckanext/datarequests/tests/test_helpers.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU Affero General Public License # along with CKAN Data Requests Extension. If not, see . -import ckanext.datarequests.helpers as helpers +from ckanext.datarequests import helpers import unittest from mock import MagicMock, patch diff --git a/ckanext/datarequests/tests/test_plugin.py b/ckanext/datarequests/tests/test_plugin.py index 3e498d13..3fc67088 100644 --- a/ckanext/datarequests/tests/test_plugin.py +++ b/ckanext/datarequests/tests/test_plugin.py @@ -17,12 +17,11 @@ # You should have received a copy of the GNU Affero General Public License # along with CKAN Data Requests Extension. If not, see . -import ckanext.datarequests.plugin as plugin -import ckanext.datarequests.constants as constants +from ckanext.datarequests import plugin, constants import unittest from mock import MagicMock, patch -from nose_parameterized import parameterized +from parameterized import parameterized TOTAL_ACTIONS = 13 COMMENTS_ACTIONS = 5 @@ -214,68 +213,81 @@ def test_before_map(self, comments_enabled): self.plg_instance.before_map(mapa) self.assertEquals(mapa_calls, mapa.connect.call_count) - mapa.connect.assert_any_call('datarequests_index', "/%s" % dr_basic_path, + mapa.connect.assert_any_call( + 'datarequests_index', "/%s" % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='index', conditions=dict(method=['GET'])) + action='index', conditions={'method': ['GET']}) - mapa.connect.assert_any_call('/%s/new' % dr_basic_path, + mapa.connect.assert_any_call( + '/%s/new' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='new', conditions=dict(method=['GET', 'POST'])) + action='new', conditions={'method': ['GET', 'POST']}) - mapa.connect.assert_any_call('show_datarequest', '/%s/{id}' % dr_basic_path, + mapa.connect.assert_any_call( + 'show_datarequest', '/%s/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='show', conditions=dict(method=['GET']), ckan_icon=mock_icon) + action='show', conditions={'method': ['GET']}, ckan_icon=mock_icon) - mapa.connect.assert_any_call('/%s/edit/{id}' % dr_basic_path, + mapa.connect.assert_any_call( + '/%s/edit/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='update', conditions=dict(method=['GET', 'POST'])) + action='update', conditions={'method': ['GET', 'POST']}) - mapa.connect.assert_any_call('/%s/delete/{id}' % dr_basic_path, + mapa.connect.assert_any_call( + '/%s/delete/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='delete', conditions=dict(method=['POST'])) + action='delete', conditions={'method': ['POST']}) - mapa.connect.assert_any_call('/%s/close/{id}' % dr_basic_path, + mapa.connect.assert_any_call( + '/%s/close/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='close', conditions=dict(method=['GET', 'POST'])) + action='close', conditions={'method': ['GET', 'POST']}) - mapa.connect.assert_any_call('organization_datarequests', + mapa.connect.assert_any_call( + 'organization_datarequests', '/organization/%s/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='organization_datarequests', conditions=dict(method=['GET']), + action='organization_datarequests', conditions={'method': ['GET']}, ckan_icon=mock_icon) - mapa.connect.assert_any_call('user_datarequests', + mapa.connect.assert_any_call( + 'user_datarequests', '/user/%s/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='user_datarequests', conditions=dict(method=['GET']), + action='user_datarequests', conditions={'method': ['GET']}, ckan_icon=mock_icon) - mapa.connect.assert_any_call('user_datarequests', + mapa.connect.assert_any_call( + 'user_datarequests', '/user/%s/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='user_datarequests', conditions=dict(method=['GET']), + action='user_datarequests', conditions={'method': ['GET']}, ckan_icon=mock_icon) - mapa.connect('/%s/follow/{id}' % dr_basic_path, + mapa.connect.assert_any_call( + '/%s/follow/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='follow', conditions=dict(method=['POST'])) + action='follow', conditions={'method': ['POST']}) - mapa.connect('/%s/unfollow/{id}' % dr_basic_path, + mapa.connect.assert_any_call( + '/%s/unfollow/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='unfollow', conditions=dict(method=['POST'])) + action='unfollow', conditions={'method': ['POST']}) if comments_enabled == 'True': - mapa.connect.assert_any_call('comment_datarequest', '/%s/comment/{id}' % dr_basic_path, + mapa.connect.assert_any_call( + 'comment_datarequest', '/%s/comment/{id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='comment', conditions=dict(method=['GET', 'POST']), ckan_icon='comment') + action='comment', conditions={'method': ['GET', 'POST']}, ckan_icon='comment') - mapa.connect.assert_any_call('/%s/comment/{datarequest_id}/delete/{comment_id}' % dr_basic_path, + mapa.connect.assert_any_call( + '/%s/comment/{datarequest_id}/delete/{comment_id}' % dr_basic_path, controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', - action='delete_comment', conditions=dict(method=['GET', 'POST'])) + action='delete_comment', conditions={'method': ['GET', 'POST']}) @parameterized.expand([ - ('True', 'True'), - ('True', 'False'), + ('True', 'True'), + ('True', 'False'), ('False', 'True'), ('False', 'False') ]) diff --git a/ckanext/datarequests/tests/test_ui_controller.py b/ckanext/datarequests/tests/test_ui_controller.py index 8a6d4bd0..2b9b3fff 100644 --- a/ckanext/datarequests/tests/test_ui_controller.py +++ b/ckanext/datarequests/tests/test_ui_controller.py @@ -17,12 +17,12 @@ # You should have received a copy of the GNU Affero General Public License # along with CKAN Data Requests Extension. If not, see . -import ckanext.datarequests.constants as constants +from ckanext.datarequests import constants import ckanext.datarequests.controllers.ui_controller as controller import unittest from mock import MagicMock -from nose_parameterized import parameterized +from parameterized import parameterized INDEX_FUNCTION = 'index' @@ -83,7 +83,6 @@ def tearDown(self): controller.base = self._base controller.constants.DATAREQUESTS_PER_PAGE = self._datarequests_per_page - ###################################################################### ################################# AUX ################################ ###################################################################### @@ -122,7 +121,6 @@ def _get_action(action): self.assertEquals(0, controller.tk.render.call_count) self.assertIsNone(result) - ###################################################################### ################################# NEW ################################ ###################################################################### @@ -160,8 +158,8 @@ def test_new_no_post(self, authorized): @parameterized.expand([ (False, False), - (True, False), - (True, True) + (True, False), + (True, True) ]) def test_new_post_content(self, authorized, validation_error): datarequest_id = 'this-represents-an-uuidv4()' @@ -219,7 +217,6 @@ def test_new_post_content(self, authorized, validation_error): controller.tk.abort.assert_called_once_with(403, 'Unauthorized to create a Data Request') self.assertEquals(0, controller.tk.render.call_count) - ###################################################################### ################################ SHOW ################################ ###################################################################### @@ -232,17 +229,17 @@ def test_show_not_found(self): @parameterized.expand({ (False, False, None), - (False, True, None), - (True, False, None), - (True, True, None), + (False, True, None), + (True, False, None), + (True, True, None), (False, False, 'uudiv4', False), - (False, True, 'uudiv4', False), - (True, False, 'uudiv4', False), - (True, True, 'uudiv4', False), + (False, True, 'uudiv4', False), + (True, False, 'uudiv4', False), + (True, True, 'uudiv4', False), (False, False, 'uudiv4', True), - (False, True, 'uudiv4', True), - (True, False, 'uudiv4', True), - (True, True, 'uudiv4', True) + (False, True, 'uudiv4', True), + (True, False, 'uudiv4', True), + (True, True, 'uudiv4', True) }) def test_show_found(self, user_show_exception, organization_show_exception, accepted_dataset, package_show_exception=False): @@ -314,7 +311,6 @@ def _get_action(action): controller.tk.render.assert_called_once_with('datarequests/show.html') self.assertEquals(controller.tk.render.return_value, result) - ###################################################################### ############################### UPDATE ############################### ###################################################################### @@ -354,8 +350,8 @@ def test_update_no_post_content(self): @parameterized.expand([ (False, False), - (True, False), - (True, True) + (True, False), + (True, True) ]) def test_update_post_content(self, authorized, validation_error): datarequest_id = 'this-represents-an-uuidv4()' @@ -432,7 +428,6 @@ def _get_action(action): controller.tk.abort.assert_called_once_with(403, 'You are not authorized to update the Data Request %s' % datarequest_id) self.assertEquals(0, controller.tk.render.call_count) - ###################################################################### ################################ INDEX ############################### ###################################################################### @@ -607,7 +602,7 @@ def _get_action(action): silly_page = 72 query_param = 'q={0}&'.format(query) if query else '' self.assertEquals("%s?%ssort=%s&page=%d" % (base_url, query_param, expected_sort, silly_page), - page_arguments['url'](q=query,page=silly_page)) + page_arguments['url'](q=query, page=silly_page)) # When URL function is called, helpers.url_for is called to get the final URL if func == INDEX_FUNCTION: @@ -636,7 +631,6 @@ def _get_action(action): self.assertEquals(controller.tk.render.return_value, result) controller.tk.render.assert_called_once_with(expected_render_page, extra_vars={'user_dict': expected_user, 'group_type': 'organization'}) - ###################################################################### ############################### DELETE ############################### ###################################################################### @@ -678,7 +672,6 @@ def test_delete(self): action='index') controller.tk.redirect_to.assert_called_once_with(controller.helpers.url_for.return_value) - ###################################################################### ################################ CLOSE ############################### ###################################################################### @@ -696,10 +689,14 @@ def test_close_not_found(self): def test_close_datarequest(self, organization): self._test_close(organization) - def _test_close(self, organization, post_content={}, errors={}, errors_summary={}, close_datarequest=MagicMock()): + def _test_close(self, organization, post_content=None, errors=None, errors_summary=None, close_datarequest=None): controller.tk.response.location = None controller.tk.response.status_int = 200 - controller.request.POST = post_content + controller.request.POST = post_content or {} + errors = errors or {} + errors_summary = errors_summary or {} + if not close_datarequest: + close_datarequest = MagicMock() datarequest_id = 'example_uuidv4' datarequest = {'id': 'uuid4', 'user_id': 'user_uuid4', 'title': 'example_title'} @@ -786,8 +783,7 @@ def test_close_post_errors(self, organization): # Execute the test self._test_close(organization, post_content, exception.error_dict, - {'Accepted Dataset': 'error1, error2'}, close_datarequest) - + {'Accepted Dataset': 'error1, error2'}, close_datarequest) ###################################################################### ############################### COMMENT ############################## @@ -898,8 +894,11 @@ def _get_action(action): controller.tk.get_action.assert_any_call(constants.UPDATE_DATAREQUEST_COMMENT) if new_comment or update_comment: - default_action.assert_called_once_with(self.expected_context, {'datarequest_id': datarequest_id, - 'comment': comment, 'id': comment_id if update_comment else ''}) + default_action.assert_called_once_with( + self.expected_context, { + 'datarequest_id': datarequest_id, + 'comment': comment, 'id': comment_id if update_comment else '' + }) if comment_or_update_exception == controller.tk.NotAuthorized: action = 'comment' if new_comment else 'update comment' @@ -915,9 +914,9 @@ def _get_action(action): # Check controller.c values self.assertEquals(comment_or_update_exception.error_dict, controller.c.errors) - errors_summary = {} - for key, error in comment_or_update_exception.error_dict.items(): - errors_summary[key] = ', '.join(error) + errors_summary = { + key: ', '.join(error) + for key, error in comment_or_update_exception.error_dict.items()} self.assertEquals(errors_summary, controller.c.errors_summary) @@ -934,7 +933,6 @@ def _get_action(action): if update_comment: self.assertEquals(comment_id, controller.c.updated_comment['id']) - ###################################################################### ########################### DELETE COMMENT ########################### ###################################################################### diff --git a/ckanext/datarequests/tests/test_validator.py b/ckanext/datarequests/tests/test_validator.py index 62ddca81..f6cbeffb 100644 --- a/ckanext/datarequests/tests/test_validator.py +++ b/ckanext/datarequests/tests/test_validator.py @@ -17,12 +17,12 @@ # You should have received a copy of the GNU Affero General Public License # along with CKAN Data Requests Extension. If not, see . -import ckanext.datarequests.validator as validator +from ckanext.datarequests import validator import unittest import random from mock import MagicMock -from nose_parameterized import parameterized +from parameterized import parameterized def generate_string(length): @@ -141,7 +141,7 @@ def test_close_valid(self): package_validator.assert_called_once_with(accepted_ds_id, context) @parameterized.expand([ - ({}, 'Comment', 'Comments must be a minimum of 1 character long'), + ({}, 'Comment', 'Comments must be a minimum of 1 character long'), ({'comment': ''}, 'Comment', 'Comments must be a minimum of 1 character long'), ({'comment': generate_string(validator.constants.COMMENT_MAX_LENGTH + 1)}, 'Comment', 'Comments must be a maximum of %d characters long' % validator.constants.COMMENT_MAX_LENGTH) @@ -164,7 +164,7 @@ def test_comment_invalid_datarequest(self): show_datarequest.side_effect = self._tk.ObjectNotFound('Store Not found') self._test_comment_invalid({'datarequest_id': 'non_existing_dr'}, 'Data Request', - 'Data Request not found') + 'Data Request not found') def test_comment_valid(self): show_datarequest = validator.tk.get_action.return_value diff --git a/ckanext/datarequests/validator.py b/ckanext/datarequests/validator.py index 0510c214..b523df04 100644 --- a/ckanext/datarequests/validator.py +++ b/ckanext/datarequests/validator.py @@ -19,7 +19,7 @@ import constants import ckan.plugins.toolkit as tk -import ckanext.datarequests.db as db +from ckanext.datarequests import db import plugin as datarequests import datetime diff --git a/requirements-dev.txt b/requirements-dev.txt index baf92481..c6544865 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ behaving==1.5.6 flake8==3.8.3 nose==1.3.7 mock -nose_parameterized==0.6.0 +parameterized==0.8.1 profanityfilter lxml==4.6.3 splinter>=0.13.0 @@ -24,4 +24,3 @@ six==1.15.0 -e git+https://github.com/qld-gov-au/ckanext-qa@develop#egg=ckanext-qa -e git+https://github.com/qld-gov-au/ckanext-archiver.git@develop#egg=ckanext-archiver -e git+https://github.com/qld-gov-au/ckanext-report.git@0.1#egg=ckanext-report - diff --git a/setup.py b/setup.py index 09130bb9..51f12ebb 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,6 @@ # along with CKAN Data Requests Extension. If not, see . from setuptools import setup, find_packages -import sys, os version = '1.1.0' @@ -27,10 +26,10 @@ version=version, description="CKAN Extension - Data Requests", long_description=''' - CKAN extension that allows users to ask for datasets that are not already published in the CKAN instance. + CKAN extension that allows users to ask for datasets that are not already published in the CKAN instance. In this way we can set up a Data Market, not only with data supplies but also with data demands. ''', - classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers keywords='', author='CoNWeT Lab.', author_email='amagan@conwet.com', @@ -46,7 +45,7 @@ # -*- Extra requirements: -*- ], tests_require=[ - 'nose_parameterized==0.6.0', + 'parameterized==0.8.1', 'selenium==3.141.0', 'coveralls==2.1.2' ], @@ -66,4 +65,4 @@ ('**/templates/**.html', 'ckan', None), ], } -) \ No newline at end of file +) diff --git a/test/features/environment.py b/test/features/environment.py index 4f824347..7ffa0e80 100644 --- a/test/features/environment.py +++ b/test/features/environment.py @@ -14,52 +14,52 @@ # @see .docker/scripts/init.sh for credentials. PERSONAS = { - 'SysAdmin': dict( - name=u'admin', - email=u'admin@localhost', - password=u'password' - ), - 'Unathenticated': dict( - name=u'', - email=u'', - password=u'' - ), + 'SysAdmin': { + 'name': u'admin', + 'email': u'admin@localhost', + 'password': u'password' + }, + 'Unathenticated': { + 'name': u'', + 'email': u'', + 'password': u'' + }, # This user will not be assigned to any organisations - 'CKANUser': dict( - name=u'ckan_user', - email=u'ckan_user@localhost', - password=u'password' - ), - 'TestOrgAdmin': dict( - name=u'test_org_admin', - email=u'test_org_admin@localhost', - password=u'password' - ), - 'TestOrgEditor': dict( - name=u'test_org_editor', - email=u'test_org_editor@localhost', - password=u'password' - ), - 'TestOrgMember': dict( - name=u'test_org_member', - email=u'test_org_member@localhost', - password=u'password' - ), - 'DataRequestOrgAdmin': dict( - name=u'dr_admin', - email=u'dr_admin@localhost', - password=u'password' - ), - 'DataRequestOrgEditor': dict( - name=u'dr_editor', - email=u'dr_editor@localhost', - password=u'password' - ), - 'DataRequestOrgMember': dict( - name=u'dr_member', - email=u'dr_member@localhost', - password=u'password' - ) + 'CKANUser': { + 'name': u'ckan_user', + 'email': u'ckan_user@localhost', + 'password': u'password' + }, + 'TestOrgAdmin': { + 'name': u'test_org_admin', + 'email': u'test_org_admin@localhost', + 'password': u'password' + }, + 'TestOrgEditor': { + 'name': u'test_org_editor', + 'email': u'test_org_editor@localhost', + 'password': u'password' + }, + 'TestOrgMember': { + 'name': u'test_org_member', + 'email': u'test_org_member@localhost', + 'password': u'password' + }, + 'DataRequestOrgAdmin': { + 'name': u'dr_admin', + 'email': u'dr_admin@localhost', + 'password': u'password' + }, + 'DataRequestOrgEditor': { + 'name': u'dr_editor', + 'email': u'dr_editor@localhost', + 'password': u'password' + }, + 'DataRequestOrgMember': { + 'name': u'dr_member', + 'email': u'dr_member@localhost', + 'password': u'password' + } } diff --git a/test/features/steps/steps.py b/test/features/steps/steps.py index 29f55c23..db53b1e4 100644 --- a/test/features/steps/steps.py +++ b/test/features/steps/steps.py @@ -7,13 +7,14 @@ import email import quopri + @step('I go to homepage') def go_to_home(context): when_i_visit_url(context, '/') + @step('I log in') def log_in(context): - assert context.persona context.execute_steps(u""" When I go to homepage @@ -22,9 +23,9 @@ def log_in(context): Then I should see an element with xpath "//a[contains(string(), 'Log out')]" """) -@step('I enter my credentials and login') -def log_in(context): +@step('I enter my credentials and login') +def submit_login(context): assert context.persona context.execute_steps(u""" When I fill in "login" with "$name" @@ -32,29 +33,29 @@ def log_in(context): And I press the element with xpath "//button[contains(string(), 'Login')]" """) + @step('I log in and go to datarequest page') def log_in_go_to_datarequest(context): - assert context.persona context.execute_steps(u""" - When I go to homepage - And I click the link with text that contains "Log in" - And I log in + When I log in And I go to datarequest page """) + @step('I go to datarequest page') def go_to_datarequest(context): when_i_visit_url(context, '/datarequest') + @step('I fill in title with random text') def title_random_text(context): - assert context.persona context.execute_steps(u""" When I fill in "title" with "Test Title {0}" """.format(random.randrange(100000))) + # The default behaving step does not convert base64 emails # Modifed the default step to decode the payload from base64 @step(u'I should receive a base64 email at "{address}" containing "{text}"') @@ -62,31 +63,30 @@ def should_receive_base64_email_containing_text(context, address, text): def filter_contents(mail): mail = email.message_from_string(mail) payload = mail.get_payload() - payload += "=" * ((4 - len(payload) % 4) % 4) # do fix the padding error issue + payload += "=" * ((4 - len(payload) % 4) % 4) # do fix the padding error issue decoded_payload = quopri.decodestring(payload).decode('base64') - print ('decoded_payload: ', decoded_payload) + print('decoded_payload: ', decoded_payload) return text in decoded_payload assert context.mail.user_messages(address, filter_contents) + @step('I log in and go to admin config page') def log_in_go_to_admin_config(context): - assert context.persona context.execute_steps(u""" - When I go to homepage - And I click the link with text that contains "Log in" - And I log in + When I log in And I go to admin config page """) + @step('I go to admin config page') def go_to_admin_config(context): when_i_visit_url(context, '/ckan-admin/config') + @step('I log in and create a datarequest') def log_in_create_a_datarequest(context): - assert context.persona context.execute_steps(u""" When I log in and go to datarequest page