Commit 2fc2207b by Renzo Lucioni

Merge pull request #5905 from edx/renzo/pep8-pylint-cleanup

Clean up pep8 and pylint violations
parents 0963372b 8d02efb0
...@@ -11,33 +11,36 @@ log = logging.getLogger(__name__) ...@@ -11,33 +11,36 @@ log = logging.getLogger(__name__)
class CourseEnrollmentError(Exception): class CourseEnrollmentError(Exception):
""" Generic Course Enrollment Error. """Generic Course Enrollment Error.
Describes any error that may occur when reading or updating enrollment information for a student or a course. Describes any error that may occur when reading or updating enrollment information for a student or a course.
""" """
def __init__(self, msg, data=None): def __init__(self, msg, data=None):
super(Exception, self).__init__(msg) super(CourseEnrollmentError, self).__init__(msg)
# Corresponding information to help resolve the error. # Corresponding information to help resolve the error.
self.data = data self.data = data
class CourseModeNotFoundError(CourseEnrollmentError): class CourseModeNotFoundError(CourseEnrollmentError):
"""The requested course mode could not be found."""
pass pass
class EnrollmentNotFoundError(CourseEnrollmentError): class EnrollmentNotFoundError(CourseEnrollmentError):
"""The requested enrollment could not be found."""
pass pass
class EnrollmentApiLoadError(CourseEnrollmentError): class EnrollmentApiLoadError(CourseEnrollmentError):
"""The data API could not be loaded."""
pass pass
DEFAULT_DATA_API = 'enrollment.data' DEFAULT_DATA_API = 'enrollment.data'
def get_enrollments(student_id): def get_enrollments(student_id):
""" Retrieves all the courses a student is enrolled in. """Retrieves all the courses a student is enrolled in.
Takes a student and retrieves all relative enrollments. Includes information regarding how the student is enrolled Takes a student and retrieves all relative enrollments. Includes information regarding how the student is enrolled
in the the course. in the the course.
...@@ -107,7 +110,7 @@ def get_enrollments(student_id): ...@@ -107,7 +110,7 @@ def get_enrollments(student_id):
def get_enrollment(student_id, course_id): def get_enrollment(student_id, course_id):
""" Retrieves all enrollment information for the student in respect to a specific course. """Retrieves all enrollment information for the student in respect to a specific course.
Gets all the course enrollment information specific to a student in a course. Gets all the course enrollment information specific to a student in a course.
...@@ -151,7 +154,7 @@ def get_enrollment(student_id, course_id): ...@@ -151,7 +154,7 @@ def get_enrollment(student_id, course_id):
def add_enrollment(student_id, course_id, mode='honor', is_active=True): def add_enrollment(student_id, course_id, mode='honor', is_active=True):
""" Enrolls a student in a course. """Enrolls a student in a course.
Enrolls a student in a course. If the mode is not specified, this will default to 'honor'. Enrolls a student in a course. If the mode is not specified, this will default to 'honor'.
...@@ -199,7 +202,7 @@ def add_enrollment(student_id, course_id, mode='honor', is_active=True): ...@@ -199,7 +202,7 @@ def add_enrollment(student_id, course_id, mode='honor', is_active=True):
def deactivate_enrollment(student_id, course_id): def deactivate_enrollment(student_id, course_id):
""" Un-enrolls a student in a course """Un-enrolls a student in a course
Deactivate the enrollment of a student in a course. We will not remove the enrollment data, but simply flag it Deactivate the enrollment of a student in a course. We will not remove the enrollment data, but simply flag it
as inactive. as inactive.
...@@ -249,7 +252,7 @@ def deactivate_enrollment(student_id, course_id): ...@@ -249,7 +252,7 @@ def deactivate_enrollment(student_id, course_id):
def update_enrollment(student_id, course_id, mode): def update_enrollment(student_id, course_id, mode):
""" Updates the course mode for the enrolled user. """Updates the course mode for the enrolled user.
Update a course enrollment for the given student and course. Update a course enrollment for the given student and course.
...@@ -295,7 +298,7 @@ def update_enrollment(student_id, course_id, mode): ...@@ -295,7 +298,7 @@ def update_enrollment(student_id, course_id, mode):
def get_course_enrollment_details(course_id): def get_course_enrollment_details(course_id):
""" Get the course modes for course. Also get enrollment start and end date, invite only, etc. """Get the course modes for course. Also get enrollment start and end date, invite only, etc.
Given a course_id, return a serializable dictionary of properties describing course enrollment information. Given a course_id, return a serializable dictionary of properties describing course enrollment information.
......
...@@ -7,7 +7,6 @@ import logging ...@@ -7,7 +7,6 @@ import logging
from django.contrib.auth.models import User from django.contrib.auth.models import User
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
from enrollment.serializers import CourseEnrollmentSerializer, CourseField from enrollment.serializers import CourseEnrollmentSerializer, CourseField
from student.models import CourseEnrollment, NonExistentCourseError from student.models import CourseEnrollment, NonExistentCourseError
...@@ -17,7 +16,7 @@ log = logging.getLogger(__name__) ...@@ -17,7 +16,7 @@ log = logging.getLogger(__name__)
def get_course_enrollments(student_id): def get_course_enrollments(student_id):
"""Retrieve a list representing all aggregated data for a student's course enrollments. """Retrieve a list representing all aggregated data for a student's course enrollments.
Construct a representation of all course enrollment data for a specific student.. Construct a representation of all course enrollment data for a specific student.
Args: Args:
student_id (str): The name of the student to retrieve course enrollment information for. student_id (str): The name of the student to retrieve course enrollment information for.
...@@ -29,7 +28,7 @@ def get_course_enrollments(student_id): ...@@ -29,7 +28,7 @@ def get_course_enrollments(student_id):
qset = CourseEnrollment.objects.filter( qset = CourseEnrollment.objects.filter(
user__username=student_id, is_active=True user__username=student_id, is_active=True
).order_by('created') ).order_by('created')
return CourseEnrollmentSerializer(qset).data return CourseEnrollmentSerializer(qset).data # pylint: disable=no-member
def get_course_enrollment(student_id, course_id): def get_course_enrollment(student_id, course_id):
...@@ -50,7 +49,7 @@ def get_course_enrollment(student_id, course_id): ...@@ -50,7 +49,7 @@ def get_course_enrollment(student_id, course_id):
enrollment = CourseEnrollment.objects.get( enrollment = CourseEnrollment.objects.get(
user__username=student_id, course_id=course_key user__username=student_id, course_id=course_key
) )
return CourseEnrollmentSerializer(enrollment).data return CourseEnrollmentSerializer(enrollment).data # pylint: disable=no-member
except CourseEnrollment.DoesNotExist: except CourseEnrollment.DoesNotExist:
return None return None
...@@ -79,7 +78,7 @@ def update_course_enrollment(student_id, course_id, mode=None, is_active=None): ...@@ -79,7 +78,7 @@ def update_course_enrollment(student_id, course_id, mode=None, is_active=None):
enrollment.update_enrollment(is_active=is_active, mode=mode) enrollment.update_enrollment(is_active=is_active, mode=mode)
enrollment.save() enrollment.save()
return CourseEnrollmentSerializer(enrollment).data return CourseEnrollmentSerializer(enrollment).data # pylint: disable=no-member
def get_course_enrollment_info(course_id): def get_course_enrollment_info(course_id):
......
...@@ -3,7 +3,6 @@ Serializers for all Course Enrollment related return objects. ...@@ -3,7 +3,6 @@ Serializers for all Course Enrollment related return objects.
""" """
from rest_framework import serializers from rest_framework import serializers
from rest_framework.fields import Field
from student.models import CourseEnrollment from student.models import CourseEnrollment
from course_modes.models import CourseMode from course_modes.models import CourseMode
...@@ -36,7 +35,7 @@ class CourseField(serializers.RelatedField): ...@@ -36,7 +35,7 @@ class CourseField(serializers.RelatedField):
def to_native(self, course): def to_native(self, course):
course_id = unicode(course.id) course_id = unicode(course.id)
course_modes = ModeSerializer(CourseMode.modes_for_course(course.id)).data course_modes = ModeSerializer(CourseMode.modes_for_course(course.id)).data # pylint: disable=no-member
return { return {
"course_id": course_id, "course_id": course_id,
......
...@@ -20,6 +20,7 @@ _ENROLLMENTS = [] ...@@ -20,6 +20,7 @@ _ENROLLMENTS = []
_COURSES = [] _COURSES = []
# pylint: disable=unused-argument
def get_course_enrollments(student_id): def get_course_enrollments(student_id):
"""Stubbed out Enrollment data request.""" """Stubbed out Enrollment data request."""
return _ENROLLMENTS return _ENROLLMENTS
...@@ -48,18 +49,21 @@ def get_course_enrollment_info(course_id): ...@@ -48,18 +49,21 @@ def get_course_enrollment_info(course_id):
def _get_fake_enrollment(student_id, course_id): def _get_fake_enrollment(student_id, course_id):
"""Get an enrollment from the enrollments array."""
for enrollment in _ENROLLMENTS: for enrollment in _ENROLLMENTS:
if student_id == enrollment['student'] and course_id == enrollment['course']['course_id']: if student_id == enrollment['student'] and course_id == enrollment['course']['course_id']:
return enrollment return enrollment
def _get_fake_course_info(course_id): def _get_fake_course_info(course_id):
"""Get a course from the courses array."""
for course in _COURSES: for course in _COURSES:
if course_id == course['course_id']: if course_id == course['course_id']:
return course return course
def add_enrollment(student_id, course_id, is_active=True, mode='honor'): def add_enrollment(student_id, course_id, is_active=True, mode='honor'):
"""Append an enrollment to the enrollments array."""
enrollment = { enrollment = {
"created": datetime.datetime.now(), "created": datetime.datetime.now(),
"mode": mode, "mode": mode,
...@@ -72,6 +76,7 @@ def add_enrollment(student_id, course_id, is_active=True, mode='honor'): ...@@ -72,6 +76,7 @@ def add_enrollment(student_id, course_id, is_active=True, mode='honor'):
def add_course(course_id, enrollment_start=None, enrollment_end=None, invite_only=False, course_modes=None): def add_course(course_id, enrollment_start=None, enrollment_end=None, invite_only=False, course_modes=None):
"""Append course to the courses array."""
course_info = { course_info = {
"course_id": course_id, "course_id": course_id,
"enrollment_end": enrollment_end, "enrollment_end": enrollment_end,
...@@ -90,7 +95,8 @@ def add_course(course_id, enrollment_start=None, enrollment_end=None, invite_onl ...@@ -90,7 +95,8 @@ def add_course(course_id, enrollment_start=None, enrollment_end=None, invite_onl
def reset(): def reset():
global _COURSES """Set the enrollments and courses arrays to be empty."""
global _COURSES # pylint: disable=global-statement
_COURSES = [] _COURSES = []
global _ENROLLMENTS global _ENROLLMENTS # pylint: disable=global-statement
_ENROLLMENTS = [] _ENROLLMENTS = []
...@@ -34,7 +34,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): ...@@ -34,7 +34,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
PASSWORD = "edx" PASSWORD = "edx"
def setUp(self): def setUp(self):
""" Create a course and user, then log in. """ """Create a course and user, then log in. """
super(EnrollmentDataTest, self).setUp() super(EnrollmentDataTest, self).setUp()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD) self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
...@@ -163,6 +163,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): ...@@ -163,6 +163,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
data.get_course_enrollment_info("this/is/bananas") data.get_course_enrollment_info("this/is/bananas")
def _create_course_modes(self, course_modes, course=None): def _create_course_modes(self, course_modes, course=None):
"""Create the course modes required for a test. """
course_id = course.id if course else self.course.id course_id = course.id if course else self.course.id
for mode_slug in course_modes: for mode_slug in course_modes:
CourseModeFactory.create( CourseModeFactory.create(
......
...@@ -60,7 +60,7 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase): ...@@ -60,7 +60,7 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
mode_display_name=mode_slug, mode_display_name=mode_slug,
) )
# Enroll in the course and verify the URL we get sent to # Create an enrollment
self._create_enrollment() self._create_enrollment()
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id)) self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
...@@ -159,6 +159,7 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase): ...@@ -159,6 +159,7 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
def _create_enrollment(self): def _create_enrollment(self):
"""Enroll in the course and verify the URL we are sent to. """
resp = self.client.post(reverse('courseenrollment', kwargs={'course_id': (unicode(self.course.id))})) resp = self.client.post(reverse('courseenrollment', kwargs={'course_id': (unicode(self.course.id))}))
self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(resp.status_code, status.HTTP_200_OK)
data = json.loads(resp.content) data = json.loads(resp.content)
......
...@@ -14,7 +14,9 @@ from student.models import NonExistentCourseError, CourseEnrollmentException ...@@ -14,7 +14,9 @@ from student.models import NonExistentCourseError, CourseEnrollmentException
class EnrollmentUserThrottle(UserRateThrottle): class EnrollmentUserThrottle(UserRateThrottle):
rate = '50/second' # TODO Limit significantly after performance testing. """Limit the number of requests users can make to the enrollment API."""
# TODO Limit significantly after performance testing. # pylint: disable=fixme
rate = '50/second'
class SessionAuthenticationAllowInactiveUser(SessionAuthentication): class SessionAuthenticationAllowInactiveUser(SessionAuthentication):
...@@ -48,7 +50,7 @@ class SessionAuthenticationAllowInactiveUser(SessionAuthentication): ...@@ -48,7 +50,7 @@ class SessionAuthenticationAllowInactiveUser(SessionAuthentication):
""" """
# Get the underlying HttpRequest object # Get the underlying HttpRequest object
request = request._request request = request._request # pylint: disable=protected-access
user = getattr(request, 'user', None) user = getattr(request, 'user', None)
# Unauthenticated, CSRF validation not required # Unauthenticated, CSRF validation not required
......
...@@ -111,7 +111,8 @@ AUTH_ENTRY_LOGIN = 'login' ...@@ -111,7 +111,8 @@ AUTH_ENTRY_LOGIN = 'login'
AUTH_ENTRY_PROFILE = 'profile' AUTH_ENTRY_PROFILE = 'profile'
AUTH_ENTRY_REGISTER = 'register' AUTH_ENTRY_REGISTER = 'register'
# TODO (ECOM-369): Repace `AUTH_ENTRY_LOGIN` and `AUTH_ENTRY_REGISTER` # pylint: disable=fixme
# TODO (ECOM-369): Replace `AUTH_ENTRY_LOGIN` and `AUTH_ENTRY_REGISTER`
# with these values once the A/B test completes, then delete # with these values once the A/B test completes, then delete
# these constants. # these constants.
AUTH_ENTRY_LOGIN_2 = 'account_login' AUTH_ENTRY_LOGIN_2 = 'account_login'
...@@ -153,6 +154,7 @@ _AUTH_ENTRY_CHOICES = frozenset([ ...@@ -153,6 +154,7 @@ _AUTH_ENTRY_CHOICES = frozenset([
# login/registration, we needed to introduce two # login/registration, we needed to introduce two
# additional end-points. Once the test completes, # additional end-points. Once the test completes,
# delete these constants from the choices list. # delete these constants from the choices list.
# pylint: disable=fixme
AUTH_ENTRY_LOGIN_2, AUTH_ENTRY_LOGIN_2,
AUTH_ENTRY_REGISTER_2, AUTH_ENTRY_REGISTER_2,
...@@ -445,6 +447,7 @@ def parse_query_params(strategy, response, *args, **kwargs): ...@@ -445,6 +447,7 @@ def parse_query_params(strategy, response, *args, **kwargs):
# TODO (ECOM-369): Delete these once the A/B test # TODO (ECOM-369): Delete these once the A/B test
# for the combined login/registration form completes. # for the combined login/registration form completes.
# pylint: disable=fixme
'is_login_2': auth_entry == AUTH_ENTRY_LOGIN_2, 'is_login_2': auth_entry == AUTH_ENTRY_LOGIN_2,
'is_register_2': auth_entry == AUTH_ENTRY_REGISTER_2, 'is_register_2': auth_entry == AUTH_ENTRY_REGISTER_2,
} }
...@@ -457,6 +460,7 @@ def parse_query_params(strategy, response, *args, **kwargs): ...@@ -457,6 +460,7 @@ def parse_query_params(strategy, response, *args, **kwargs):
# these kwargs in `redirect_to_supplementary_form`, but # these kwargs in `redirect_to_supplementary_form`, but
# these should redirect to the same location as "is_login" and "is_register" # these should redirect to the same location as "is_login" and "is_register"
# (whichever login/registration end-points win in the test). # (whichever login/registration end-points win in the test).
# pylint: disable=fixme
@partial.partial @partial.partial
def ensure_user_information( def ensure_user_information(
strategy, strategy,
...@@ -500,7 +504,7 @@ def ensure_user_information( ...@@ -500,7 +504,7 @@ def ensure_user_information(
return HttpResponseBadRequest() return HttpResponseBadRequest()
# TODO (ECOM-369): Consolidate this with `dispatch_to_login` # TODO (ECOM-369): Consolidate this with `dispatch_to_login`
# once the A/B test completes. # once the A/B test completes. # pylint: disable=fixme
dispatch_to_login_2 = is_login_2 and (user_unset or user_inactive) dispatch_to_login_2 = is_login_2 and (user_unset or user_inactive)
if is_dashboard or is_profile: if is_dashboard or is_profile:
...@@ -510,7 +514,7 @@ def ensure_user_information( ...@@ -510,7 +514,7 @@ def ensure_user_information(
return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN], name='signin_user') return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN], name='signin_user')
# TODO (ECOM-369): Consolidate this with `dispatch_to_login` # TODO (ECOM-369): Consolidate this with `dispatch_to_login`
# once the A/B test completes. # once the A/B test completes. # pylint: disable=fixme
if dispatch_to_login_2: if dispatch_to_login_2:
return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN_2]) return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN_2])
...@@ -518,7 +522,7 @@ def ensure_user_information( ...@@ -518,7 +522,7 @@ def ensure_user_information(
return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_REGISTER], name='register_user') return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_REGISTER], name='register_user')
# TODO (ECOM-369): Consolidate this with `is_register` # TODO (ECOM-369): Consolidate this with `is_register`
# once the A/B test completes. # once the A/B test completes. # pylint: disable=fixme
if is_register_2 and user_unset: if is_register_2 and user_unset:
return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_REGISTER_2]) return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_REGISTER_2])
......
...@@ -8,7 +8,6 @@ information and preferences). ...@@ -8,7 +8,6 @@ information and preferences).
""" """
from django.conf import settings from django.conf import settings
from django.db import transaction, IntegrityError from django.db import transaction, IntegrityError
from django.db.models import Q
from django.core.validators import validate_email, validate_slug, ValidationError from django.core.validators import validate_email, validate_slug, ValidationError
from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.forms import PasswordResetForm
......
...@@ -53,6 +53,10 @@ def set_course_tag(user, course_id, key, value): ...@@ -53,6 +53,10 @@ def set_course_tag(user, course_id, key, value):
key: arbitrary (<=255 char string) key: arbitrary (<=255 char string)
value: arbitrary string value: arbitrary string
""" """
# pylint: disable=W0511
# TODO: There is a risk of IntegrityErrors being thrown here given
# simultaneous calls from many processes. Handle by retrying after
# a short delay?
record, _ = UserCourseTag.objects.get_or_create( record, _ = UserCourseTag.objects.get_or_create(
user=user, user=user,
...@@ -61,6 +65,3 @@ def set_course_tag(user, course_id, key, value): ...@@ -61,6 +65,3 @@ def set_course_tag(user, course_id, key, value):
record.value = value record.value = value
record.save() record.save()
# TODO: There is a risk of IntegrityErrors being thrown here given
# simultaneous calls from many processes. Handle by retrying after a short delay?
...@@ -72,9 +72,9 @@ def require_post_params(required_params): ...@@ -72,9 +72,9 @@ def require_post_params(required_params):
HttpResponse HttpResponse
""" """
def _decorator(func): def _decorator(func): # pylint: disable=missing-docstring
@wraps(func) @wraps(func)
def _wrapped(*args, **kwargs): def _wrapped(*args, **_kwargs): # pylint: disable=missing-docstring
request = args[0] request = args[0]
missing_params = set(required_params) - set(request.POST.keys()) missing_params = set(required_params) - set(request.POST.keys())
if len(missing_params) > 0: if len(missing_params) > 0:
...@@ -339,7 +339,7 @@ def shim_student_view(view_func, check_logged_in=False): ...@@ -339,7 +339,7 @@ def shim_student_view(view_func, check_logged_in=False):
""" """
@wraps(view_func) @wraps(view_func)
def _inner(request): def _inner(request): # pylint: disable=missing-docstring
# Ensure that the POST querydict is mutable # Ensure that the POST querydict is mutable
request.POST = request.POST.copy() request.POST = request.POST.copy()
......
...@@ -250,4 +250,4 @@ SORTED_COUNTRIES = [ ...@@ -250,4 +250,4 @@ SORTED_COUNTRIES = [
(u'ZM', u'Zambia'), (u'ZM', u'Zambia'),
(u'ZW', u'Zimbabwe'), (u'ZW', u'Zimbabwe'),
(u'AX', u'\xc5land Islands') (u'AX', u'\xc5land Islands')
] ]
\ No newline at end of file
...@@ -14,12 +14,12 @@ from user_api.helpers import ( ...@@ -14,12 +14,12 @@ from user_api.helpers import (
class FakeInputException(Exception): class FakeInputException(Exception):
"""Fake exception that should be intercepted. """ """Fake exception that should be intercepted."""
pass pass
class FakeOutputException(Exception): class FakeOutputException(Exception):
"""Fake exception that should be raised. """ """Fake exception that should be raised."""
pass pass
...@@ -36,9 +36,7 @@ def intercepted_function(raise_error=None): ...@@ -36,9 +36,7 @@ def intercepted_function(raise_error=None):
class InterceptErrorsTest(TestCase): class InterceptErrorsTest(TestCase):
""" """Tests for the decorator that intercepts errors."""
Tests for the decorator that intercepts errors.
"""
@raises(FakeOutputException) @raises(FakeOutputException)
def test_intercepts_errors(self): def test_intercepts_errors(self):
...@@ -73,7 +71,7 @@ class InterceptErrorsTest(TestCase): ...@@ -73,7 +71,7 @@ class InterceptErrorsTest(TestCase):
class FormDescriptionTest(TestCase): class FormDescriptionTest(TestCase):
"""Tests of helper functions which generate form descriptions."""
def test_to_json(self): def test_to_json(self):
desc = FormDescription("post", "/submit") desc = FormDescription("post", "/submit")
desc.add_field( desc.add_field(
...@@ -134,7 +132,7 @@ class FormDescriptionTest(TestCase): ...@@ -134,7 +132,7 @@ class FormDescriptionTest(TestCase):
@ddt.ddt @ddt.ddt
class StudentViewShimTest(TestCase): class StudentViewShimTest(TestCase):
"Tests of the student view shim."
def setUp(self): def setUp(self):
self.captured_request = None self.captured_request = None
...@@ -211,8 +209,8 @@ class StudentViewShimTest(TestCase): ...@@ -211,8 +209,8 @@ class StudentViewShimTest(TestCase):
response = view(HttpRequest()) response = view(HttpRequest())
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
def _shimmed_view(self, response, check_logged_in=False): def _shimmed_view(self, response, check_logged_in=False): # pylint: disable=missing-docstring
def stub_view(request): def stub_view(request): # pylint: disable=missing-docstring
self.captured_request = request self.captured_request = request
return response return response
return shim_student_view(stub_view, check_logged_in=check_logged_in) return shim_student_view(stub_view, check_logged_in=check_logged_in)
...@@ -112,6 +112,11 @@ class ApiTestCase(TestCase): ...@@ -112,6 +112,11 @@ class ApiTestCase(TestCase):
self.assertEqual(response.status_code, 405) self.assertEqual(response.status_code, 405)
def assertAuthDisabled(self, method, uri): def assertAuthDisabled(self, method, uri):
"""
Assert that the Django rest framework does not interpret basic auth
headers for views exposed to anonymous users as an attempt to authenticate.
"""
# Django rest framework interprets basic auth headers # Django rest framework interprets basic auth headers
# as an attempt to authenticate with the API. # as an attempt to authenticate with the API.
# We don't want this for views available to anonymous users. # We don't want this for views available to anonymous users.
...@@ -987,7 +992,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -987,7 +992,7 @@ class RegistrationViewTest(ApiTestCase):
) )
def test_register_form_year_of_birth(self): def test_register_form_year_of_birth(self):
this_year = datetime.datetime.now(UTC).year this_year = datetime.datetime.now(UTC).year # pylint: disable=maybe-no-member
year_options = ( year_options = (
[{"value": "", "name": "--", "default": True}] + [ [{"value": "", "name": "--", "default": True}] + [
{"value": unicode(year), "name": unicode(year)} {"value": unicode(year), "name": unicode(year)}
...@@ -1067,13 +1072,17 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1067,13 +1072,17 @@ class RegistrationViewTest(ApiTestCase):
self._assert_reg_field( self._assert_reg_field(
{"honor_code": "required"}, {"honor_code": "required"},
{ {
"label": "I agree to the <a href=\"https://www.test.com/honor\">Terms of Service and Honor Code</a>", "label": "I agree to the {platform_name} <a href=\"https://www.test.com/honor\">Terms of Service and Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
),
"name": "honor_code", "name": "honor_code",
"defaultValue": False, "defaultValue": False,
"type": "checkbox", "type": "checkbox",
"required": True, "required": True,
"errorMessages": { "errorMessages": {
"required": "You must agree to the <a href=\"https://www.test.com/honor\">Terms of Service and Honor Code</a>" "required": "You must agree to the {platform_name} <a href=\"https://www.test.com/honor\">Terms of Service and Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
)
} }
} }
) )
...@@ -1084,13 +1093,17 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1084,13 +1093,17 @@ class RegistrationViewTest(ApiTestCase):
self._assert_reg_field( self._assert_reg_field(
{"honor_code": "required"}, {"honor_code": "required"},
{ {
"label": "I agree to the <a href=\"/honor\">Terms of Service and Honor Code</a>", "label": "I agree to the {platform_name} <a href=\"/honor\">Terms of Service and Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
),
"name": "honor_code", "name": "honor_code",
"defaultValue": False, "defaultValue": False,
"type": "checkbox", "type": "checkbox",
"required": True, "required": True,
"errorMessages": { "errorMessages": {
"required": "You must agree to the <a href=\"/honor\">Terms of Service and Honor Code</a>" "required": "You must agree to the {platform_name} <a href=\"/honor\">Terms of Service and Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
)
} }
} }
) )
...@@ -1107,13 +1120,17 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1107,13 +1120,17 @@ class RegistrationViewTest(ApiTestCase):
self._assert_reg_field( self._assert_reg_field(
{"honor_code": "required", "terms_of_service": "required"}, {"honor_code": "required", "terms_of_service": "required"},
{ {
"label": "I agree to the <a href=\"https://www.test.com/honor\">Honor Code</a>", "label": "I agree to the {platform_name} <a href=\"https://www.test.com/honor\">Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
),
"name": "honor_code", "name": "honor_code",
"defaultValue": False, "defaultValue": False,
"type": "checkbox", "type": "checkbox",
"required": True, "required": True,
"errorMessages": { "errorMessages": {
"required": "You must agree to the <a href=\"https://www.test.com/honor\">Honor Code</a>" "required": "You must agree to the {platform_name} <a href=\"https://www.test.com/honor\">Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
)
} }
} }
) )
...@@ -1122,13 +1139,17 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1122,13 +1139,17 @@ class RegistrationViewTest(ApiTestCase):
self._assert_reg_field( self._assert_reg_field(
{"honor_code": "required", "terms_of_service": "required"}, {"honor_code": "required", "terms_of_service": "required"},
{ {
"label": "I agree to the <a href=\"https://www.test.com/tos\">Terms of Service</a>", "label": "I agree to the {platform_name} <a href=\"https://www.test.com/tos\">Terms of Service</a>.".format(
platform_name=settings.PLATFORM_NAME
),
"name": "terms_of_service", "name": "terms_of_service",
"defaultValue": False, "defaultValue": False,
"type": "checkbox", "type": "checkbox",
"required": True, "required": True,
"errorMessages": { "errorMessages": {
"required": "You must agree to the <a href=\"https://www.test.com/tos\">Terms of Service</a>" "required": "You must agree to the {platform_name} <a href=\"https://www.test.com/tos\">Terms of Service</a>.".format(
platform_name=settings.PLATFORM_NAME
)
} }
} }
) )
...@@ -1141,13 +1162,17 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1141,13 +1162,17 @@ class RegistrationViewTest(ApiTestCase):
self._assert_reg_field( self._assert_reg_field(
{"honor_code": "required", "terms_of_service": "required"}, {"honor_code": "required", "terms_of_service": "required"},
{ {
"label": "I agree to the <a href=\"/honor\">Honor Code</a>", "label": "I agree to the {platform_name} <a href=\"/honor\">Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
),
"name": "honor_code", "name": "honor_code",
"defaultValue": False, "defaultValue": False,
"type": "checkbox", "type": "checkbox",
"required": True, "required": True,
"errorMessages": { "errorMessages": {
"required": "You must agree to the <a href=\"/honor\">Honor Code</a>" "required": "You must agree to the {platform_name} <a href=\"/honor\">Honor Code</a>.".format(
platform_name=settings.PLATFORM_NAME
)
} }
} }
) )
...@@ -1156,13 +1181,17 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1156,13 +1181,17 @@ class RegistrationViewTest(ApiTestCase):
self._assert_reg_field( self._assert_reg_field(
{"honor_code": "required", "terms_of_service": "required"}, {"honor_code": "required", "terms_of_service": "required"},
{ {
"label": "I agree to the <a href=\"/tos\">Terms of Service</a>", "label": "I agree to the {platform_name} <a href=\"/tos\">Terms of Service</a>.".format(
platform_name=settings.PLATFORM_NAME
),
"name": "terms_of_service", "name": "terms_of_service",
"defaultValue": False, "defaultValue": False,
"type": "checkbox", "type": "checkbox",
"required": True, "required": True,
"errorMessages": { "errorMessages": {
"required": "You must agree to the <a href=\"/tos\">Terms of Service</a>" "required": "You must agree to the {platform_name} <a href=\"/tos\">Terms of Service</a>.".format(
platform_name=settings.PLATFORM_NAME
)
} }
} }
) )
...@@ -1372,7 +1401,7 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1372,7 +1401,7 @@ class RegistrationViewTest(ApiTestCase):
self.assertEqual(response.status_code, 409) self.assertEqual(response.status_code, 409)
self.assertEqual( self.assertEqual(
response.content, response.content,
"It looks like {} belongs to an existing account. Try again with a different email address and username.".format( "It looks like {} belongs to an existing account. Try again with a different username.".format(
self.USERNAME self.USERNAME
) )
) )
......
# pylint: disable=missing-docstring
from django.conf import settings from django.conf import settings
from django.conf.urls import include, patterns, url from django.conf.urls import include, patterns, url
from rest_framework import routers from rest_framework import routers
......
"""HTTP end-points for the User API. """ """HTTP end-points for the User API. """
import copy import copy
import json
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -25,7 +24,6 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey ...@@ -25,7 +24,6 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey
from edxmako.shortcuts import marketing_link from edxmako.shortcuts import marketing_link
import third_party_auth import third_party_auth
from microsite_configuration import microsite
from user_api.api import account as account_api, profile as profile_api from user_api.api import account as account_api, profile as profile_api
from user_api.helpers import FormDescription, shim_student_view, require_post_params from user_api.helpers import FormDescription, shim_student_view, require_post_params
...@@ -54,7 +52,7 @@ class LoginSessionView(APIView): ...@@ -54,7 +52,7 @@ class LoginSessionView(APIView):
# so do not require authentication. # so do not require authentication.
authentication_classes = [] authentication_classes = []
def get(self, request): def get(self, request): # pylint: disable=unused-argument
"""Return a description of the login form. """Return a description of the login form.
This decouples clients from the API definition: This decouples clients from the API definition:
...@@ -64,9 +62,6 @@ class LoginSessionView(APIView): ...@@ -64,9 +62,6 @@ class LoginSessionView(APIView):
See `user_api.helpers.FormDescription` for examples See `user_api.helpers.FormDescription` for examples
of the JSON-encoded form description. of the JSON-encoded form description.
Arguments:
request (HttpRequest)
Returns: Returns:
HttpResponse HttpResponse
...@@ -307,6 +302,15 @@ class RegistrationView(APIView): ...@@ -307,6 +302,15 @@ class RegistrationView(APIView):
return shim_student_view(create_account)(request) return shim_student_view(create_account)(request)
def _add_email_field(self, form_desc, required=True): def _add_email_field(self, form_desc, required=True):
"""Add an email field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's email address. # meant to hold the user's email address.
email_label = _(u"Email") email_label = _(u"Email")
...@@ -328,6 +332,15 @@ class RegistrationView(APIView): ...@@ -328,6 +332,15 @@ class RegistrationView(APIView):
) )
def _add_name_field(self, form_desc, required=True): def _add_name_field(self, form_desc, required=True):
"""Add a name field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's full name. # meant to hold the user's full name.
name_label = _(u"Full Name") name_label = _(u"Full Name")
...@@ -347,6 +360,15 @@ class RegistrationView(APIView): ...@@ -347,6 +360,15 @@ class RegistrationView(APIView):
) )
def _add_username_field(self, form_desc, required=True): def _add_username_field(self, form_desc, required=True):
"""Add a username field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's public username. # meant to hold the user's public username.
username_label = _(u"Username") username_label = _(u"Username")
...@@ -369,6 +391,15 @@ class RegistrationView(APIView): ...@@ -369,6 +391,15 @@ class RegistrationView(APIView):
) )
def _add_password_field(self, form_desc, required=True): def _add_password_field(self, form_desc, required=True):
"""Add a password field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's password. # meant to hold the user's password.
password_label = _(u"Password") password_label = _(u"Password")
...@@ -385,6 +416,15 @@ class RegistrationView(APIView): ...@@ -385,6 +416,15 @@ class RegistrationView(APIView):
) )
def _add_level_of_education_field(self, form_desc, required=True): def _add_level_of_education_field(self, form_desc, required=True):
"""Add a level of education field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a dropdown menu on the registration # Translators: This label appears above a dropdown menu on the registration
# form used to select the user's highest completed level of education. # form used to select the user's highest completed level of education.
education_level_label = _(u"Highest Level of Education Completed") education_level_label = _(u"Highest Level of Education Completed")
...@@ -399,6 +439,15 @@ class RegistrationView(APIView): ...@@ -399,6 +439,15 @@ class RegistrationView(APIView):
) )
def _add_gender_field(self, form_desc, required=True): def _add_gender_field(self, form_desc, required=True):
"""Add a gender field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a dropdown menu on the registration # Translators: This label appears above a dropdown menu on the registration
# form used to select the user's gender. # form used to select the user's gender.
gender_label = _(u"Gender") gender_label = _(u"Gender")
...@@ -413,6 +462,15 @@ class RegistrationView(APIView): ...@@ -413,6 +462,15 @@ class RegistrationView(APIView):
) )
def _add_year_of_birth_field(self, form_desc, required=True): def _add_year_of_birth_field(self, form_desc, required=True):
"""Add a year of birth field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a dropdown menu on the registration # Translators: This label appears above a dropdown menu on the registration
# form used to select the user's year of birth. # form used to select the user's year of birth.
yob_label = _(u"Year of Birth") yob_label = _(u"Year of Birth")
...@@ -428,6 +486,15 @@ class RegistrationView(APIView): ...@@ -428,6 +486,15 @@ class RegistrationView(APIView):
) )
def _add_mailing_address_field(self, form_desc, required=True): def _add_mailing_address_field(self, form_desc, required=True):
"""Add a mailing address field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# meant to hold the user's mailing address. # meant to hold the user's mailing address.
mailing_address_label = _(u"Mailing Address") mailing_address_label = _(u"Mailing Address")
...@@ -440,6 +507,15 @@ class RegistrationView(APIView): ...@@ -440,6 +507,15 @@ class RegistrationView(APIView):
) )
def _add_goals_field(self, form_desc, required=True): def _add_goals_field(self, form_desc, required=True):
"""Add a goals field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This phrase appears above a field on the registration form # Translators: This phrase appears above a field on the registration form
# meant to hold the user's reasons for registering with edX. # meant to hold the user's reasons for registering with edX.
goals_label = _( goals_label = _(
...@@ -454,6 +530,15 @@ class RegistrationView(APIView): ...@@ -454,6 +530,15 @@ class RegistrationView(APIView):
) )
def _add_city_field(self, form_desc, required=True): def _add_city_field(self, form_desc, required=True):
"""Add a city field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a field on the registration form # Translators: This label appears above a field on the registration form
# which allows the user to input the city in which they live. # which allows the user to input the city in which they live.
city_label = _(u"City") city_label = _(u"City")
...@@ -465,6 +550,15 @@ class RegistrationView(APIView): ...@@ -465,6 +550,15 @@ class RegistrationView(APIView):
) )
def _add_country_field(self, form_desc, required=True): def _add_country_field(self, form_desc, required=True):
"""Add a country field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This label appears above a dropdown menu on the registration # Translators: This label appears above a dropdown menu on the registration
# form used to select the country in which the user lives. # form used to select the country in which the user lives.
country_label = _(u"Country") country_label = _(u"Country")
...@@ -486,6 +580,15 @@ class RegistrationView(APIView): ...@@ -486,6 +580,15 @@ class RegistrationView(APIView):
) )
def _add_honor_code_field(self, form_desc, required=True): def _add_honor_code_field(self, form_desc, required=True):
"""Add an honor code field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Separate terms of service and honor code checkboxes # Separate terms of service and honor code checkboxes
if self._is_field_visible("terms_of_service"): if self._is_field_visible("terms_of_service"):
terms_text = _(u"Honor Code") terms_text = _(u"Honor Code")
...@@ -531,6 +634,15 @@ class RegistrationView(APIView): ...@@ -531,6 +634,15 @@ class RegistrationView(APIView):
) )
def _add_terms_of_service_field(self, form_desc, required=True): def _add_terms_of_service_field(self, form_desc, required=True):
"""Add a terms of service field to a form description.
Arguments:
form_desc: A form description
Keyword Arguments:
required (Boolean): Whether this field is required; defaults to True
"""
# Translators: This is a legal document users must agree to # Translators: This is a legal document users must agree to
# in order to register a new account. # in order to register a new account.
terms_text = _(u"Terms of Service") terms_text = _(u"Terms of Service")
...@@ -615,6 +727,7 @@ class RegistrationView(APIView): ...@@ -615,6 +727,7 @@ class RegistrationView(APIView):
restrictions={} restrictions={}
) )
class PasswordResetView(APIView): class PasswordResetView(APIView):
"""HTTP end-point for GETting a description of the password reset form. """ """HTTP end-point for GETting a description of the password reset form. """
...@@ -622,7 +735,7 @@ class PasswordResetView(APIView): ...@@ -622,7 +735,7 @@ class PasswordResetView(APIView):
# so do not require authentication. # so do not require authentication.
authentication_classes = [] authentication_classes = []
def get(self, request): def get(self, request): # pylint: disable=unused-argument
"""Return a description of the password reset form. """Return a description of the password reset form.
This decouples clients from the API definition: This decouples clients from the API definition:
...@@ -632,9 +745,6 @@ class PasswordResetView(APIView): ...@@ -632,9 +745,6 @@ class PasswordResetView(APIView):
See `user_api.helpers.FormDescription` for examples See `user_api.helpers.FormDescription` for examples
of the JSON-encoded form description. of the JSON-encoded form description.
Arguments:
request (HttpRequest)
Returns: Returns:
HttpResponse HttpResponse
......
...@@ -20,6 +20,7 @@ class UrlResetMixin(object): ...@@ -20,6 +20,7 @@ class UrlResetMixin(object):
""" """
def _reset_urls(self, urlconf_modules): def _reset_urls(self, urlconf_modules):
"""Reset `urls.py` for a set of Django apps."""
for urlconf in urlconf_modules: for urlconf in urlconf_modules:
if urlconf in sys.modules: if urlconf in sys.modules:
reload(sys.modules[urlconf]) reload(sys.modules[urlconf])
......
"""Helper functions for the student account app. """ """Helper functions for the student account app. """
# TODO: move this function here instead of importing it from student # TODO: move this function here instead of importing it from student # pylint: disable=fixme
from student.helpers import auth_pipeline_urls from student.helpers import auth_pipeline_urls # pylint: disable=unused-import
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment