Merge pull request #21384 from edx/bom/python-3-swarm

Bom/python 3 swarm
This commit is contained in:
Feanil Patel
2019-08-21 09:27:59 -04:00
committed by GitHub
30 changed files with 62 additions and 78 deletions

View File

@@ -254,7 +254,7 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
resp = self.client.get_html(course_details_url)
self.assertEqual(
feature_flags[2],
'<h3 id="heading-entrance-exam">' in resp.content
b'<h3 id="heading-entrance-exam">' in resp.content
)
@override_settings(MKTG_URLS={'ROOT': 'dummy-root'})

View File

@@ -538,7 +538,7 @@ def _update_asset(request, course_key, asset_key):
# update existing asset
try:
modified_asset = json.loads(request.body)
modified_asset = json.loads(request.body.decode('utf8'))
except ValueError:
return HttpResponseBadRequest()
contentstore().set_attr(asset_key, 'locked', modified_asset['locked'])

View File

@@ -349,7 +349,7 @@ def certificate_activation_handler(request, course_key_string):
msg = _(u'PermissionDenied: Failed in authenticating {user}').format(user=request.user)
return JsonResponse({"error": msg}, status=403)
data = json.loads(request.body)
data = json.loads(request.body.decode('utf8'))
is_active = data.get('is_active', False)
certificates = CertificateManager.get_certificates(course)

View File

@@ -225,7 +225,10 @@ def xblock_handler(request, usage_key_string):
request.user,
request.json.get('display_name'),
)
return JsonResponse({'locator': unicode(dest_usage_key), 'courseKey': unicode(dest_usage_key.course_key)})
return JsonResponse({
'locator': text_type(dest_usage_key),
'courseKey': text_type(dest_usage_key.course_key)
})
else:
return _create_item(request)
elif request.method == 'PATCH':
@@ -323,14 +326,14 @@ def xblock_view_handler(request, usage_key_string, view_name):
xblock.runtime.wrappers.append(partial(
wrap_xblock,
'StudioRuntime',
usage_id_serializer=unicode,
usage_id_serializer=text_type,
request_token=request_token(request),
))
xblock.runtime.wrappers_asides.append(partial(
wrap_xblock_aside,
'StudioRuntime',
usage_id_serializer=unicode,
usage_id_serializer=text_type,
request_token=request_token(request),
extra_classes=['wrapper-comp-plugins']
))
@@ -508,7 +511,7 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None,
store.revert_to_published(xblock.location, user.id)
# Returning the same sort of result that we do for other save operations. In the future,
# we may want to return the full XBlockInfo.
return JsonResponse({'id': unicode(xblock.location)})
return JsonResponse({'id': text_type(xblock.location)})
old_metadata = own_metadata(xblock)
old_content = xblock.get_explicitly_set_fields_by_scope(Scope.content)
@@ -615,7 +618,7 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None,
store.update_item(course, user.id)
result = {
'id': unicode(xblock.location),
'id': text_type(xblock.location),
'data': data,
'metadata': own_metadata(xblock)
}
@@ -692,7 +695,7 @@ def _create_item(request):
)
return JsonResponse(
{'locator': unicode(created_block.location), 'courseKey': unicode(created_block.location.course_key)}
{'locator': text_type(created_block.location), 'courseKey': text_type(created_block.location.course_key)}
)
@@ -724,7 +727,7 @@ def is_source_item_in_target_parents(source_item, target_parent):
"""
target_ancestors = _create_xblock_ancestor_info(target_parent, is_concise=True)['ancestors']
for target_ancestor in target_ancestors:
if unicode(source_item.location) == target_ancestor['id']:
if text_type(source_item.location) == target_ancestor['id']:
return True
return False
@@ -782,15 +785,15 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non
error = _('You can not move an item directly into content experiment.')
elif source_index is None:
error = _(u'{source_usage_key} not found in {parent_usage_key}.').format(
source_usage_key=unicode(source_usage_key),
parent_usage_key=unicode(source_parent.location)
source_usage_key=text_type(source_usage_key),
parent_usage_key=text_type(source_parent.location)
)
else:
try:
target_index = int(target_index) if target_index is not None else None
if len(target_parent.children) < target_index:
error = _(u'You can not move {source_usage_key} at an invalid index ({target_index}).').format(
source_usage_key=unicode(source_usage_key),
source_usage_key=text_type(source_usage_key),
target_index=target_index
)
except ValueError:
@@ -813,15 +816,15 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non
log.info(
u'MOVE: %s moved from %s to %s at %d index',
unicode(source_usage_key),
unicode(source_parent.location),
unicode(target_parent_usage_key),
text_type(source_usage_key),
text_type(source_parent.location),
text_type(target_parent_usage_key),
insert_at
)
context = {
'move_source_locator': unicode(source_usage_key),
'parent_locator': unicode(target_parent_usage_key),
'move_source_locator': text_type(source_usage_key),
'parent_locator': text_type(target_parent_usage_key),
'source_index': target_index if target_index is not None else source_index
}
return JsonResponse(context)
@@ -956,7 +959,7 @@ def orphan_handler(request, course_key_string):
course_usage_key = CourseKey.from_string(course_key_string)
if request.method == 'GET':
if has_studio_read_access(request.user, course_usage_key):
return JsonResponse([unicode(item) for item in modulestore().get_orphans(course_usage_key)])
return JsonResponse([text_type(item) for item in modulestore().get_orphans(course_usage_key)])
else:
raise PermissionDenied()
if request.method == 'DELETE':
@@ -984,7 +987,7 @@ def _delete_orphans(course_usage_key, user_id, commit=False):
if branch == ModuleStoreEnum.BranchName.published:
revision = ModuleStoreEnum.RevisionOption.published_only
store.delete_item(itemloc, user_id, revision=revision)
return [unicode(item) for item in items]
return [text_type(item) for item in items]
def _get_xblock(usage_key, user):
@@ -1004,7 +1007,7 @@ def _get_xblock(usage_key, user):
raise
except InvalidLocationError:
log.error("Can't find item by location.")
return JsonResponse({"error": "Can't find item by location: " + unicode(usage_key)}, 404)
return JsonResponse({"error": "Can't find item by location: " + text_type(usage_key)}, 404)
def _get_module_info(xblock, rewrite_static_links=True, include_ancestor_info=False, include_publishing_info=False):
@@ -1056,7 +1059,7 @@ def _get_gating_info(course, xblock):
setattr(course, 'gating_prerequisites', gating_api.get_prerequisites(course.id))
info["is_prereq"] = gating_api.is_prerequisite(course.id, xblock.location)
info["prereqs"] = [
p for p in course.gating_prerequisites if unicode(xblock.location) not in p['namespace']
p for p in course.gating_prerequisites if text_type(xblock.location) not in p['namespace']
]
prereq, prereq_min_score, prereq_min_completion = gating_api.get_required_content(
course.id,
@@ -1158,7 +1161,7 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
pct_sign=_('%'))
xblock_info = {
'id': unicode(xblock.location),
'id': text_type(xblock.location),
'display_name': xblock.display_name_with_default,
'category': xblock.category,
'has_children': xblock.has_children

View File

@@ -17,7 +17,7 @@ def handler_url(block, handler_name, suffix='', query='', thirdparty=False):
raise NotImplementedError("edX Studio doesn't support third-party xblock handler urls")
url = reverse('component_handler', kwargs={
'usage_key_string': six.text_type(block.scope_ids.usage_id).encode('utf-8'),
'usage_key_string': six.text_type(block.scope_ids.usage_id),
'handler': handler_name,
'suffix': suffix,
}).rstrip('/')

View File

@@ -135,7 +135,7 @@ class CourseEnrollmentFactory(DjangoModelFactory):
def _create(cls, model_class, *args, **kwargs):
manager = cls._get_manager(model_class)
course_kwargs = {}
for key in kwargs.keys():
for key in list(kwargs):
if key.startswith('course__'):
course_kwargs[key.split('__')[1]] = kwargs.pop(key)

View File

@@ -121,7 +121,7 @@ def server_track(request, event_type, event, page=None):
"event_source": "server",
"event_type": event_type,
"event": event,
"agent": _get_request_header(request, 'HTTP_USER_AGENT').decode('latin1'),
"agent": _get_request_header(request, 'HTTP_USER_AGENT').encode().decode('latin1'),
"page": page,
"time": datetime.datetime.utcnow().replace(tzinfo=pytz.utc),
"host": _get_request_header(request, 'SERVER_NAME'),

View File

@@ -46,7 +46,7 @@ def expect_json(view_function):
# e.g. 'charset', so we can't do a direct string compare
if "application/json" in request.META.get('CONTENT_TYPE', '') and request.body:
try:
request.json = json.loads(request.body)
request.json = json.loads(request.body.decode('utf8'))
except ValueError:
return JsonResponseBadRequest({"error": "Invalid JSON"})
else:

View File

@@ -17,7 +17,7 @@ def fasthash(string):
Hashes `string` into a string representation of a 128-bit digest.
"""
md4 = hashlib.new("md4")
md4.update(string)
md4.update(string.encode('utf-8'))
return md4.hexdigest()

View File

@@ -66,8 +66,9 @@ def clean_course_key(course_key, padding_char):
padding_char (str): Character used for padding at end of the encoded
string. The standard value for this is '='.
"""
encoded = b32encode(six.text_type(course_key).encode('utf8')).decode('utf8')
return "course_{}".format(
b32encode(six.text_type(course_key)).replace('=', padding_char)
encoded.replace('=', padding_char)
)

View File

@@ -425,7 +425,7 @@ def _get_modulestore_branch_setting():
# compare hostname against the regex expressions set of mappings which will tell us which branch to use
if mappings:
for key in mappings.iterkeys():
for key in mappings:
if re.match(key, hostname):
return mappings[key]
if branch is None:

View File

@@ -859,7 +859,7 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase, Mongo
course_key = self.fill_in_run(course_key)
parent_cache = self._get_parent_cache(self.get_branch_setting())
while to_process and depth is None or depth >= 0:
while to_process and (depth is None or depth >= 0):
children = []
for item in to_process:
self._clean_item_data(item)

View File

@@ -11,7 +11,6 @@ import sys
from collections import defaultdict
from contextlib import contextmanager
from importlib import import_module
from io import BytesIO
import six
from fs.osfs import OSFS
@@ -49,16 +48,6 @@ etree.set_default_parser(edx_xml_parser)
log = logging.getLogger(__name__)
# VS[compat]
# TODO (cpennington): Remove this once all fall 2012 courses have been imported
# into the cms from xml
def clean_out_mako_templating(xml_string):
orig_xml = xml_string
xml_string = xml_string.replace('%include', 'include')
xml_string = re.sub(r"(?m)^\s*%.*$", '', xml_string)
return xml_string
class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
def __init__(self, xmlstore, course_id, course_dir,
error_tracker,
@@ -171,10 +160,6 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
xml_data.set('url_name', url_name)
try:
# VS[compat]
# TODO (cpennington): Remove this once all fall 2012 courses
# have been imported into the cms from xml
xml = clean_out_mako_templating(xml)
xml_data = etree.fromstring(xml)
make_name_unique(xml_data)
@@ -450,12 +435,6 @@ class XMLModuleStore(ModuleStoreReadBase):
"""
log.debug('========> Starting courselike import from %s', course_dir)
with open(self.data_dir / course_dir / self.parent_xml) as course_file:
# VS[compat]
# TODO (cpennington): Remove this once all fall 2012 courses have
# been imported into the cms from xml
course_file = BytesIO(clean_out_mako_templating(course_file.read()))
course_data = etree.parse(course_file, parser=edx_xml_parser).getroot()
org = course_data.get('org')

View File

@@ -57,7 +57,7 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
response = self.client.get(url)
email_section = '<div class="vert-left send-email" id="section-send-email">'
# If this fails, it is likely because BulkEmailFlag.is_enabled() is set to False
self.assertIn(email_section, response.content)
self.assertIn(email_section, response.content.decode('utf-8'))
def test_optout_course(self):
"""

View File

@@ -313,7 +313,7 @@ def save_ccx(request, course, ccx=None):
return earliest, ccx_ids_to_delete
graded = {}
earliest, ccx_ids_to_delete = override_fields(course, json.loads(request.body), graded, [])
earliest, ccx_ids_to_delete = override_fields(course, json.loads(request.body.decode('utf8')), graded, [])
bulk_delete_ccx_override_fields(ccx, ccx_ids_to_delete)
if earliest:
override_field_for_ccx(ccx, course, 'start', earliest)

View File

@@ -61,7 +61,7 @@ class CourseDateSummaryTest(SharedModuleStoreTestCase):
self.client.login(username=user.username, password=TEST_PASSWORD)
url = reverse('info', args=(course.id,))
response = self.client.get(url)
self.assertNotIn('date-summary', response.content)
self.assertNotIn(b'date-summary', response.content)
def test_course_home_logged_out(self):
course = create_course_run()

View File

@@ -1633,7 +1633,7 @@ def financial_assistance(_request):
def financial_assistance_request(request):
"""Submit a request for financial assistance to Zendesk."""
try:
data = json.loads(request.body)
data = json.loads(request.body.decode('utf8'))
# Simple sanity check that the session belongs to the user
# submitting an FA request
username = data['username']

View File

@@ -906,7 +906,7 @@ def is_comment_too_deep(parent):
return (
MAX_COMMENT_DEPTH is not None and (
MAX_COMMENT_DEPTH < 0 or
(parent and parent["depth"] >= MAX_COMMENT_DEPTH)
(parent and (parent["depth"] or 0) >= MAX_COMMENT_DEPTH)
)
)

View File

@@ -205,7 +205,7 @@ def edxnotes_visibility(request, course_id):
raise Http404
try:
visibility = json.loads(request.body)["visibility"]
visibility = json.loads(request.body.decode('utf8'))["visibility"]
course_module.edxnotes_visibility = visibility
course_module.save()
return JsonResponse(status=200)

View File

@@ -79,7 +79,7 @@ class BlockRecordList(object):
supported by adding a label indicated which algorithm was used, e.g.,
"sha256$j0NDRmSPa5bfid2pAcUXaxCm2Dlh3TwayItZstwyeqQ=".
"""
return b64encode(sha1(self.json_value).digest())
return b64encode(sha1(self.json_value.encode('utf-8')).digest())
@lazy
def json_value(self):

View File

@@ -93,7 +93,7 @@ class GradesTransformer(BlockStructureTransformer):
separators=(',', ':'), # Remove spaces from separators for more compact representation
sort_keys=True,
)
return b64encode(sha1(ordered_policy).digest())
return b64encode(sha1(ordered_policy.encode('utf-8')).digest())
@classmethod
def _collect_explicit_graded(cls, block_structure):

View File

@@ -83,7 +83,7 @@ class TestGradebook(SharedModuleStoreTestCase):
args=(text_type(self.course.id),)
))
self.assertEquals(self.response.status_code, 200)
self.assertEqual(self.response.status_code, 200)
class TestDefaultGradingPolicy(TestGradebook):
@@ -98,17 +98,17 @@ class TestDefaultGradingPolicy(TestGradebook):
def test_default_policy(self):
# Default >= 50% passes, so Users 5-10 should be passing for Homework 1 [6]
# One use at the top of the page [1]
self.assertEquals(7, self.response.content.count('grade_Pass'))
self.assertEqual(7, self.response.content.count(b'grade_Pass'))
# Users 1-5 attempted Homework 1 (and get Fs) [4]
# Users 1-10 attempted any homework (and get Fs) [10]
# Users 4-10 scored enough to not get rounded to 0 for the class (and get Fs) [7]
# One use at top of the page [1]
self.assertEquals(22, self.response.content.count('grade_F'))
self.assertEqual(22, self.response.content.count(b'grade_F'))
# All other grades are None [29 categories * 11 users - 27 non-empty grades = 292]
# One use at the top of the page [1]
self.assertEquals(293, self.response.content.count('grade_None'))
self.assertEqual(293, self.response.content.count(b'grade_None'))
class TestLetterCutoffPolicy(TestGradebook):
@@ -145,29 +145,29 @@ class TestLetterCutoffPolicy(TestGradebook):
# Users 9-10 have >= 90% on Homeworks [2]
# Users 9-10 have >= 90% on the class [2]
# One use at the top of the page [1]
self.assertEquals(5, self.response.content.count('grade_A'))
self.assertEqual(5, self.response.content.count(b'grade_A'))
# User 8 has 80 <= Homeworks < 90 [1]
# User 8 has 80 <= class < 90 [1]
# One use at the top of the page [1]
self.assertEquals(3, self.response.content.count('grade_B'))
self.assertEqual(3, self.response.content.count(b'grade_B'))
# User 7 has 70 <= Homeworks < 80 [1]
# User 7 has 70 <= class < 80 [1]
# One use at the top of the page [1]
self.assertEquals(3, self.response.content.count('grade_C'))
self.assertEqual(3, self.response.content.count(b'grade_C'))
# User 6 has 60 <= Homeworks < 70 [1]
# User 6 has 60 <= class < 70 [1]
# One use at the top of the page [1]
self.assertEquals(3, self.response.content.count('grade_C'))
self.assertEqual(3, self.response.content.count(b'grade_C'))
# Users 1-5 have 60% > grades > 0 on Homeworks [5]
# Users 1-5 have 60% > grades > 0 on the class [5]
# One use at top of the page [1]
self.assertEquals(11, self.response.content.count('grade_F'))
self.assertEqual(11, self.response.content.count(b'grade_F'))
# User 0 has 0 on Homeworks [1]
# User 0 has 0 on the class [1]
# One use at the top of the page [1]
self.assertEquals(3, self.response.content.count('grade_None'))
self.assertEqual(3, self.response.content.count(b'grade_None'))

View File

@@ -3273,7 +3273,7 @@ def parse_request_data(request):
:return: dict object containing parsed json data.
"""
try:
data = json.loads(request.body or '{}')
data = json.loads(request.body.decode('utf8') or u'{}')
except ValueError:
raise ValueError(_('The record is not in the correct format. Please add a valid username or email address.'))

View File

@@ -739,7 +739,7 @@ def _section_send_email(course, access):
usage_id_serializer=lambda usage_id: quote_slashes(six.text_type(usage_id)),
# Generate a new request_token here at random, because this module isn't connected to any other
# xblock rendering.
request_token=uuid.uuid1().get_hex()
request_token=uuid.uuid1().hex
)
cohorts = []
if is_course_cohorted(course_key):

View File

@@ -320,7 +320,7 @@ def submit_bulk_course_email(request, course_key, email_id):
task_input = {'email_id': email_id, 'to_option': targets}
task_key_stub = str(email_id)
# create the key value by using MD5 hash:
task_key = hashlib.md5(task_key_stub).hexdigest()
task_key = hashlib.md5(task_key_stub.encode('utf-8')).hexdigest()
return submit_task(request, task_type, task_class, course_key, task_input, task_key)

View File

@@ -140,7 +140,7 @@ def _get_xmodule_instance_args(request, task_id):
request_info = {'username': request.user.username,
'user_id': request.user.id,
'ip': request.META['REMOTE_ADDR'],
'agent': request.META.get('HTTP_USER_AGENT', '').decode('latin1'),
'agent': request.META.get('HTTP_USER_AGENT', '').encode().decode('latin1'),
'host': request.META['SERVER_NAME'],
}

View File

@@ -51,7 +51,7 @@ def handler_url(block, handler_name, suffix='', query='', thirdparty=False):
url = reverse(view_name, kwargs={
'course_id': six.text_type(block.location.course_key),
'usage_id': quote_slashes(six.text_type(block.scope_ids.usage_id).encode('utf-8')),
'usage_id': quote_slashes(six.text_type(block.scope_ids.usage_id)),
'handler': handler_name,
'suffix': suffix,
})

View File

@@ -59,7 +59,7 @@ if course_key:
}
if not course_id:
user_metadata['course_id'] = unicode(course_key)
user_metadata['course_id'] = six.text_type(course_key)
elif isinstance(course_key, six.string_types):
user_metadata['course_id'] = course_key

View File

@@ -1,6 +1,7 @@
<%page expression_filter="h"/>
<%! from django.utils.translation import ugettext as _ %>
<form action="${action}" method="post">
% for pk, pv in params.iteritems():
% for pk, pv in params.items():
<input type="hidden" name="${pk}" value="${pv}" />
% endfor

View File

@@ -22,7 +22,7 @@ def update_session_language(request):
"""
response = HttpResponse(200)
if request.method == 'PATCH':
data = json.loads(request.body)
data = json.loads(request.body.decode('utf8'))
language = data.get(LANGUAGE_KEY, settings.LANGUAGE_CODE)
if request.session.get(LANGUAGE_SESSION_KEY, None) != language:
request.session[LANGUAGE_SESSION_KEY] = six.text_type(language)