From 69797ff2f0a70c6344d1a80a5639592d9daf957d Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 10 Apr 2020 10:23:38 -0700 Subject: [PATCH] Add Django 2.2 support (#262) Implement the changes to support Django 2.2 and remove Python 2 support fully. Co-authored-by: Guruprasad Lakshmi Narayanan --- Makefile | 2 +- README.md | 5 +- circle.yml | 63 +------- problem_builder/answer.py | 4 +- problem_builder/completion.py | 2 +- problem_builder/dashboard.py | 8 +- problem_builder/dashboard_visual.py | 2 +- problem_builder/instructor_tool.py | 2 +- problem_builder/mcq.py | 6 +- problem_builder/mentoring.py | 10 +- problem_builder/message.py | 4 +- .../migrations/0002_auto_20160121_1525.py | 4 +- problem_builder/mixins.py | 14 +- problem_builder/models.py | 6 +- problem_builder/mrq.py | 2 +- problem_builder/plot.py | 6 +- problem_builder/questionnaire.py | 2 +- problem_builder/slider.py | 4 +- problem_builder/step.py | 2 +- problem_builder/step_review.py | 2 +- problem_builder/sub_api.py | 2 +- problem_builder/table.py | 12 +- .../tests/integration/base_test.py | 12 +- .../tests/integration/test_completion.py | 3 +- .../tests/integration/test_dashboard.py | 4 +- .../tests/integration/test_instructor_tool.py | 6 +- .../tests/integration/test_mentoring.py | 2 +- .../tests/integration/test_slider.py | 2 +- .../tests/integration/test_step_builder.py | 16 +- .../tests/integration/test_table.py | 2 +- .../tests/integration/test_titles.py | 2 +- .../tests/unit/test_instructor_tool.py | 6 +- problem_builder/tests/unit/test_migration.py | 2 +- problem_builder/tests/unit/test_mixins.py | 8 +- problem_builder/tests/unit/test_models.py | 2 +- .../tests/unit/test_problem_builder.py | 7 +- problem_builder/tests/unit/test_step.py | 4 +- .../tests/unit/test_step_builder.py | 2 +- problem_builder/tests/unit/test_swipe.py | 2 +- problem_builder/tests/unit/utils.py | 6 +- problem_builder/tip.py | 2 +- problem_builder/utils.py | 4 +- problem_builder/v1/xml_changes.py | 2 +- pylintrc | 3 +- requirements-dev.txt | 8 +- requirements.txt | 5 +- setup.py | 2 +- test_requirements.in | 11 +- test_requirements.txt | 148 +++++++++--------- xblock-sdk | 2 +- 50 files changed, 199 insertions(+), 240 deletions(-) diff --git a/Makefile b/Makefile index ac7f5836..ad6f3564 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ help: ## display this help message @perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}' upgrade: - pip-compile --output-file test_requirements.txt test_requirements.in + pip-compile --upgrade --output-file test_requirements.txt test_requirements.in extract_translations: ## extract strings to be translated, outputting .po files cd $(WORKING_DIR) && i18n_tool extract diff --git a/README.md b/README.md index 0170ea86..f9e24e2b 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ create its migrations: ```bash (venv) ~/xblock_development/problem-builder $ cd ../venv/src/xblock-sdk -(venv) ~/xblock_development/venv/src/xblock-sdk $ make pip +(venv) ~/xblock_development/venv/src/xblock-sdk $ make install (venv) ~/xblock_development/venv/src/xblock-sdk $ python manage.py makemigrations workbench ``` @@ -221,6 +221,9 @@ Problem Builder releases are tagged with a version number, e.g. [`v2.6.5`](https://github.com/open-craft/problem-builder/tree/v2.6.5). We recommend installing the most recently tagged version, with the exception of the following compatibility issues: +* `edx-platform` version `open-release/ironwood.2` and earlier must use + ≤[v3.4.14](https://github.com/open-craft/problem-builder/tree/v3.4.14). See + [PR 262](https://github.com/open-craft/problem-builder/pull/262) for details. * `edx-platform` version `open-release/eucalyptus.2` and earlier must use ≤[v2.6.0](https://github.com/open-craft/problem-builder/tree/v2.6.0). See [PR 128](https://github.com/open-craft/problem-builder/pull/128) for details. diff --git a/circle.yml b/circle.yml index 8d233dcd..b09601e4 100644 --- a/circle.yml +++ b/circle.yml @@ -3,6 +3,10 @@ jobs: build: docker: - image: <> + - image: circleci/mysql:5.6 + command: mysqld --character-set-server=latin1 --collation-server=latin1_swedish_ci + environment: + MYSQL_ROOT_PASSWORD: rootpw parameters: test_command: type: string @@ -10,13 +14,14 @@ jobs: type: string environment: MOZ_HEADLESS: 1 + WORKBENCH_DATABASES: '{"default": {"ENGINE": "django.db.backends.mysql", "NAME": "db", "USER": "root", "PASSWORD": "rootpw", "HOST": "127.0.0.1", "OPTIONS": {"charset": "utf8mb4"}}}' steps: - checkout - run: name: Update system command: | sudo apt-get update - sudo apt-get install -y libgtk3.0-cil-dev libasound2 libasound2 libdbus-glib-1-2 libdbus-1-3 libgtk2.0-0 + sudo apt-get install -y libgtk3.0-cil-dev libasound2 libasound2 libdbus-glib-1-2 libdbus-1-3 libgtk2.0-0 default-libmysqlclient-dev - run: name: Install geckodriver command: | @@ -68,7 +73,7 @@ jobs: sudo apt-get update virtualenv venv source venv/bin/activate - pip install 'coverage<5' + pip install 'coverage==5.0.3' - attach_workspace: at: /tmp/workspace - run: @@ -125,60 +130,6 @@ workflows: version: 2 build_and_deploy: jobs: - - build: - name: py27-quality - test_command: make quality - docker_image: circleci/python:2.7-buster-browsers - filters: - tags: - only: /.*/ - - build: - name: py27-unit - test_command: make test.unit - docker_image: circleci/python:2.7-buster-browsers - filters: - tags: - only: /.*/ - - build: - name: py27-integration - test_command: make test.integration - docker_image: circleci/python:2.7-buster-browsers - filters: - tags: - only: /.*/ - - coverage: - name: py27-coverage - docker_image: circleci/python:2.7-buster - filters: - tags: - only: /.*/ - requires: - - py27-quality - - py27-unit - - py27-integration - - deploy: - name: py27-deploy-sdist - docker_image: circleci/python:2.7-buster - dist_type: sdist - requires: - - py27-coverage - filters: - tags: - only: /v[0-9]+(\.[0-9]+)*/ - branches: - ignore: /.*/ - - deploy: - name: py27-deploy-bdist_wheel - docker_image: circleci/python:2.7-buster - dist_type: bdist_wheel - requires: - - py27-coverage - filters: - tags: - only: /v[0-9]+(\.[0-9]+)*/ - branches: - ignore: /.*/ - - build: name: py35-quality test_command: make quality diff --git a/problem_builder/answer.py b/problem_builder/answer.py index 52dafcc8..2d1a0e0a 100644 --- a/problem_builder/answer.py +++ b/problem_builder/answer.py @@ -184,7 +184,7 @@ def mentoring_view(self, context=None): context['answer_editable_id'] = uuid.uuid4().hex[:15] context['self'] = self context['hide_header'] = context.get('hide_header', False) or not self.show_title - html = loader.render_template('templates/html/answer_editable.html', context) + html = loader.render_django_template('templates/html/answer_editable.html', context) fragment = Fragment(html) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/answer.css')) @@ -332,7 +332,7 @@ def mentoring_view(self, context=None): context['student_input'] = None else: context['student_input'] = self.student_input - html = loader.render_template('templates/html/answer_read_only.html', context) + html = loader.render_django_template('templates/html/answer_read_only.html', context) fragment = Fragment(html) fragment.add_css_url(self.runtime.local_resource_url(self, self.css_path)) diff --git a/problem_builder/completion.py b/problem_builder/completion.py index d97a375c..3931b6d3 100644 --- a/problem_builder/completion.py +++ b/problem_builder/completion.py @@ -144,7 +144,7 @@ def mentoring_view(self, context): context['title'] = self.display_name_with_default context['hide_header'] = context.get('hide_header', False) or not self.show_title - html = loader.render_template('templates/html/completion.html', context) + html = loader.render_django_template('templates/html/completion.html', context) fragment = Fragment(html) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/completion.js')) diff --git a/problem_builder/dashboard.py b/problem_builder/dashboard.py index 1f661a44..20f8fb13 100644 --- a/problem_builder/dashboard.py +++ b/problem_builder/dashboard.py @@ -59,7 +59,7 @@ def _(text): # Classes ########################################################### -class ExportMixin(object): +class ExportMixin: """ Used by blocks which need to provide a downloadable export. """ @@ -92,7 +92,7 @@ def _get_course_name(self): return "" -class ColorRule(object): +class ColorRule: """ A rule used to conditionally set colors @@ -457,14 +457,14 @@ def student_view(self, context=None): # pylint: disable=unused-argument blocks, rules_parsed, self.color_for_value, self.visual_title, self.visual_desc ) - report_template = loader.render_template('templates/html/dashboard_report.html', { + report_template = loader.render_django_template('templates/html/dashboard_report.html', { 'title': self.display_name, 'css': loader.load_unicode(self.css_path), 'student_name': self._get_user_full_name(), 'course_name': self._get_course_name(), }) - html = loader.render_template('templates/html/dashboard.html', { + html = loader.render_django_template('templates/html/dashboard.html', { 'blocks': blocks, 'display_name': self.display_name, 'visual_repr': visual_repr, diff --git a/problem_builder/dashboard_visual.py b/problem_builder/dashboard_visual.py index 4e5e51b7..dc3887dc 100644 --- a/problem_builder/dashboard_visual.py +++ b/problem_builder/dashboard_visual.py @@ -29,7 +29,7 @@ """ -class DashboardVisualData(object): +class DashboardVisualData: """ Data about the visual representation of a dashboard. """ diff --git a/problem_builder/instructor_tool.py b/problem_builder/instructor_tool.py index 37696deb..e0652d67 100644 --- a/problem_builder/instructor_tool.py +++ b/problem_builder/instructor_tool.py @@ -142,7 +142,7 @@ def student_view(self, context=None): _('Long Answer'): 'AnswerBlock', } - html = loader.render_template('templates/html/instructor_tool.html', { + html = loader.render_django_template('templates/html/instructor_tool.html', { 'block_choices': block_choices, 'course_blocks_api': COURSE_BLOCKS_API, 'root_block_id': six.text_type(getattr(self.runtime, 'course_id', 'course_id')), diff --git a/problem_builder/mcq.py b/problem_builder/mcq.py index 1b0325a2..4ba60dd2 100644 --- a/problem_builder/mcq.py +++ b/problem_builder/mcq.py @@ -101,7 +101,7 @@ def calculate_results(self, submission): formatted_tips = None if tips_html: - formatted_tips = loader.render_template('templates/html/tip_choice_group.html', { + formatted_tips = loader.render_django_template('templates/html/tip_choice_group.html', { 'tips_html': tips_html, }) @@ -239,7 +239,7 @@ def get_author_edit_view_fragment(self, context): show them in the author edit view, for clarity. """ fragment = Fragment() - fragment.add_content(loader.render_template('templates/html/ratingblock_edit_preview.html', { + fragment.add_content(loader.render_django_template('templates/html/ratingblock_edit_preview.html', { 'question': self.question, 'low': self.low, 'high': self.high, @@ -265,7 +265,7 @@ def student_view(self, context): if context: # Workbench does not provide context rendering_for_studio = context.get('author_edit_view') if rendering_for_studio: - fragment.add_content(loader.render_template('templates/html/rating_edit_footer.html', { + fragment.add_content(loader.render_django_template('templates/html/rating_edit_footer.html', { "url_name": self.url_name })) return fragment diff --git a/problem_builder/mentoring.py b/problem_builder/mentoring.py index 22e0feb6..c1f0ebcb 100644 --- a/problem_builder/mentoring.py +++ b/problem_builder/mentoring.py @@ -214,7 +214,7 @@ def author_preview_view(self, context): authors in Studio when not editing this block's children. """ fragment = self.student_view(context) - fragment.add_content(loader.render_template('templates/html/mentoring_url_name.html', { + fragment.add_content(loader.render_django_template('templates/html/mentoring_url_name.html', { "url_name": self.url_name })) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder-edit.css')) @@ -609,7 +609,7 @@ def submit(self, submissions, suffix=''): # server-side check that the user is allowed to submit: if self.max_attempts_reached: raise JsonHandlerError(403, "Maximum number of attempts already reached.") - elif self.has_missing_dependency: + if self.has_missing_dependency: raise JsonHandlerError( 403, "You need to complete all previous steps before being able to complete the current one." @@ -742,7 +742,7 @@ def author_edit_view(self, context): local_context = context.copy() local_context['author_edit_view'] = True fragment = super(MentoringBlock, self).author_edit_view(local_context) - fragment.add_content(loader.render_template('templates/html/mentoring_url_name.html', { + fragment.add_content(loader.render_django_template('templates/html/mentoring_url_name.html', { 'url_name': self.url_name })) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css')) @@ -851,7 +851,7 @@ def active_step_safe(self): added/deleted. """ active_step = self.active_step - if active_step >= 0 and active_step < len(self.step_ids): + if 0 <= active_step < len(self.step_ids): return active_step if active_step == -1 and self.has_review_step: return active_step # -1 indicates the review step @@ -1107,7 +1107,7 @@ def author_edit_view(self, context): Add some HTML to the author view that allows authors to add child blocks. """ fragment = super(MentoringWithExplicitStepsBlock, self).author_edit_view(context) - fragment.add_content(loader.render_template('templates/html/mentoring_url_name.html', { + fragment.add_content(loader.render_django_template('templates/html/mentoring_url_name.html', { "url_name": self.url_name })) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css')) diff --git a/problem_builder/message.py b/problem_builder/message.py index a0128f4e..10896ddb 100644 --- a/problem_builder/message.py +++ b/problem_builder/message.py @@ -168,12 +168,12 @@ def parse_xml(cls, node, runtime, keys, id_generator): return block -class CompletedMentoringMessageShim(object): +class CompletedMentoringMessageShim: CATEGORY = 'pb-message' STUDIO_LABEL = _("Message (Complete)") -class IncompleteMentoringMessageShim(object): +class IncompleteMentoringMessageShim: CATEGORY = 'pb-message' STUDIO_LABEL = _("Message (Incomplete)") diff --git a/problem_builder/migrations/0002_auto_20160121_1525.py b/problem_builder/migrations/0002_auto_20160121_1525.py index 0de9475c..b6f8be44 100644 --- a/problem_builder/migrations/0002_auto_20160121_1525.py +++ b/problem_builder/migrations/0002_auto_20160121_1525.py @@ -20,8 +20,8 @@ class Migration(migrations.Migration): ('submission_uid', models.CharField(max_length=32)), ('block_id', models.CharField(max_length=255, db_index=True)), ('notified', models.BooleanField(default=False, db_index=True)), - ('shared_by', models.ForeignKey(related_name='problem_builder_shared_by', to=settings.AUTH_USER_MODEL)), - ('shared_with', models.ForeignKey(related_name='problem_builder_shared_with', to=settings.AUTH_USER_MODEL)), + ('shared_by', models.ForeignKey(related_name='problem_builder_shared_by', on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL)), + ('shared_with', models.ForeignKey(related_name='problem_builder_shared_with', on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), migrations.AlterUniqueTogether( diff --git a/problem_builder/mixins.py b/problem_builder/mixins.py index ce9b8e9d..3d85c1fb 100644 --- a/problem_builder/mixins.py +++ b/problem_builder/mixins.py @@ -31,7 +31,7 @@ def _normalize_id(key): return key -class XBlockWithTranslationServiceMixin(object): +class XBlockWithTranslationServiceMixin: """ Mixin providing access to i18n service """ @@ -80,7 +80,7 @@ def display_name_with_default(self): return self._(self.CAPTION) -class StepParentMixin(object): +class StepParentMixin: """ An XBlock mixin for a parent block containing Step children """ @@ -100,7 +100,7 @@ def steps(self): return [self.runtime.get_block(child_id) for child_id in self.step_ids] -class MessageParentMixin(object): +class MessageParentMixin: """ An XBlock mixin for a parent block containing MentoringMessageBlock children """ @@ -167,7 +167,7 @@ def author_preview_view(self, context): return self.student_view(context) -class NoSettingsMixin(object): +class NoSettingsMixin: """ Mixin for an XBlock that has no settings """ def studio_view(self, _context=None): @@ -175,7 +175,7 @@ def studio_view(self, _context=None): return Fragment(u'

{}

'.format(self._("This XBlock does not have any settings."))) -class StudentViewUserStateMixin(object): +class StudentViewUserStateMixin: """ Mixin to provide student_view_user_state view. @@ -234,7 +234,7 @@ def student_view_user_state(self, context=None, suffix=''): ) -class StudentViewUserStateResultsTransformerMixin(object): +class StudentViewUserStateResultsTransformerMixin: """ A convenient way for MentoringBlock and MentoringStepBlock to share student_results transform code. @@ -267,7 +267,7 @@ def delete_key(self, dictionary, key): return dictionary -class ExpandStaticURLMixin(object): +class ExpandStaticURLMixin: def expand_static_url(self, text): """ diff --git a/problem_builder/models.py b/problem_builder/models.py index be1c226e..e005b6f9 100644 --- a/problem_builder/models.py +++ b/problem_builder/models.py @@ -68,13 +68,13 @@ class Share(models.Model): to query for arbitrary anonymous user IDs. In order to make sharing work, we have to store them here. """ - shared_by = models.ForeignKey(User, related_name='problem_builder_shared_by') + shared_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='problem_builder_shared_by') submission_uid = models.CharField(max_length=32) block_id = models.CharField(max_length=255, db_index=True) - shared_with = models.ForeignKey(User, related_name='problem_builder_shared_with') + shared_with = models.ForeignKey(User, on_delete=models.CASCADE, related_name='problem_builder_shared_with') notified = models.BooleanField(default=False, db_index=True) - class Meta(object): + class Meta: # Since problem_builder isn't added to INSTALLED_APPS until it's imported, # specify the app_label here. app_label = 'problem_builder' diff --git a/problem_builder/mrq.py b/problem_builder/mrq.py index bb6f3cdf..e487b9d4 100644 --- a/problem_builder/mrq.py +++ b/problem_builder/mrq.py @@ -157,7 +157,7 @@ def calculate_results(self, submissions): loader = ResourceLoader(__name__) choice_result['completed'] = choice_completed - choice_result['tips'] = loader.render_template('templates/html/tip_choice_group.html', { + choice_result['tips'] = loader.render_django_template('templates/html/tip_choice_group.html', { 'tips_html': choice_tips_html, }) diff --git a/problem_builder/plot.py b/problem_builder/plot.py index 92fc6b3b..0aa8ac53 100644 --- a/problem_builder/plot.py +++ b/problem_builder/plot.py @@ -327,7 +327,7 @@ def claims_display(self): def author_preview_view(self, context): context['self'] = self fragment = Fragment() - fragment.add_content(loader.render_template('templates/html/plot_preview.html', context)) + fragment.add_content(loader.render_django_template('templates/html/plot_preview.html', context)) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/plot-preview.css')) if self.overlay_ids: fragment.add_content( @@ -349,7 +349,7 @@ def student_view(self, context=None): context['hide_header'] = True context['self'] = self fragment = Fragment() - fragment.add_content(loader.render_template('templates/html/plot.html', context)) + fragment.add_content(loader.render_django_template('templates/html/plot.html', context)) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/plot.css')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/vendor/d3.min.js')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/plot.js')) @@ -481,6 +481,6 @@ def mentoring_view(self, context): def student_view(self, context): context['self'] = self fragment = Fragment() - fragment.add_content(loader.render_template('templates/html/overlay.html', context)) + fragment.add_content(loader.render_django_template('templates/html/overlay.html', context)) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/overlay.css')) return fragment diff --git a/problem_builder/questionnaire.py b/problem_builder/questionnaire.py index 9deece32..aa255888 100644 --- a/problem_builder/questionnaire.py +++ b/problem_builder/questionnaire.py @@ -171,7 +171,7 @@ def author_edit_view(self, context): self.get_parent().get_parent() if self.get_parent() else None, MentoringWithExplicitStepsBlock ) - fragment.add_content(loader.render_template('templates/html/questionnaire_add_buttons.html', { + fragment.add_content(loader.render_django_template('templates/html/questionnaire_add_buttons.html', { 'show_review': show_review })) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/problem-builder.css')) diff --git a/problem_builder/slider.py b/problem_builder/slider.py index d820fe83..0e88db78 100644 --- a/problem_builder/slider.py +++ b/problem_builder/slider.py @@ -115,7 +115,7 @@ def mentoring_view(self, context): context['instructions_string'] = self._("Select a value from {min_label} to {max_label}").format( min_label=self.min_label, max_label=self.max_label ) - html = loader.render_template('templates/html/slider.html', context) + html = loader.render_django_template('templates/html/slider.html', context) fragment = Fragment(html) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/slider.js')) @@ -145,7 +145,7 @@ def author_view(self, context): """ context['hide_header'] = True # Header is already shown in the Studio wrapper fragment = self.student_view(context) - fragment.add_content(loader.render_template('templates/html/slider_edit_footer.html', { + fragment.add_content(loader.render_django_template('templates/html/slider_edit_footer.html', { "url_name": self.url_name })) return fragment diff --git a/problem_builder/step.py b/problem_builder/step.py index 9f4e2a16..691535f5 100644 --- a/problem_builder/step.py +++ b/problem_builder/step.py @@ -67,7 +67,7 @@ def _normalize_id(key): return key -class Correctness(object): +class Correctness: CORRECT = 'correct' PARTIAL = 'partial' INCORRECT = 'incorrect' diff --git a/problem_builder/step_review.py b/problem_builder/step_review.py index 4a3b1aed..3d5d701c 100644 --- a/problem_builder/step_review.py +++ b/problem_builder/step_review.py @@ -213,7 +213,7 @@ def student_view(self, context=None): """ Render the per-question feedback, if any. """ review_tips = (context or {}).get("score_summary", {}).get("review_tips") if review_tips: - html = loader.render_template("templates/html/sb-review-per-question-feedback.html", { + html = loader.render_django_template("templates/html/sb-review-per-question-feedback.html", { 'tips': review_tips, }) else: diff --git a/problem_builder/sub_api.py b/problem_builder/sub_api.py index e5403c77..529d15aa 100644 --- a/problem_builder/sub_api.py +++ b/problem_builder/sub_api.py @@ -30,7 +30,7 @@ sub_api = None # We are probably in the workbench. Don't use the submissions API -class SubmittingXBlockMixin(object): +class SubmittingXBlockMixin: """ Simplifies use of the submissions API by an XBlock. """ diff --git a/problem_builder/table.py b/problem_builder/table.py index ea529a38..2669465c 100644 --- a/problem_builder/table.py +++ b/problem_builder/table.py @@ -130,7 +130,7 @@ def table_render(self, data, suffix=''): content_values.append(child_frag.content) context['header_values'] = header_values if any(header_values) else None context['content_values'] = content_values - html = loader.render_template('templates/html/mentoring-table.html', context) + html = loader.render_django_template('templates/html/mentoring-table.html', context) return {'content': html} @property @@ -147,7 +147,7 @@ def get_shared_list(self, data, suffix=''): ).values_list('shared_with__username', flat=True) } return { - 'content': loader.render_template('templates/html/mentoring-table-shared-list.html', context) + 'content': loader.render_django_template('templates/html/mentoring-table-shared-list.html', context) } @XBlock.json_handler @@ -266,14 +266,14 @@ def student_view(self, context): else: raise - report_template = loader.render_template('templates/html/mentoring-table-report.html', { + report_template = loader.render_django_template('templates/html/mentoring-table-report.html', { 'title': self.display_name, 'css': loader.load_unicode(AnswerRecapBlock.css_path) + loader.load_unicode(self.css_path), 'student_name': self._get_user_full_name(), 'course_name': self._get_course_name(), }) - fragment.add_content(loader.render_template('templates/html/mentoring-table-container.html', context)) + fragment.add_content(loader.render_django_template('templates/html/mentoring-table-container.html', context)) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/mentoring-table.css')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/vendor/jquery-shorten.js')) fragment.add_javascript_url(self.runtime.local_resource_url(self, self.js_path)) @@ -295,7 +295,7 @@ def author_edit_view(self, context): Add some HTML to the author view that allows authors to add choices and tips. """ fragment = super(MentoringTableBlock, self).author_edit_view(context) - fragment.add_content(loader.render_template('templates/html/mentoring-table-add-button.html', {})) + fragment.add_content(loader.render_django_template('templates/html/mentoring-table-add-button.html', {})) # Share styles with the questionnaire edit CSS: fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/questionnaire-edit.css')) return fragment @@ -345,7 +345,7 @@ def author_edit_view(self, context): """ fragment = super(MentoringTableColumn, self).author_edit_view(context) fragment.content = u"
{}
".format(self.header) + fragment.content - fragment.add_content(loader.render_template('templates/html/mentoring-column-add-button.html', {})) + fragment.add_content(loader.render_django_template('templates/html/mentoring-column-add-button.html', {})) # Share styles with the questionnaire edit CSS: fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/questionnaire-edit.css')) return fragment diff --git a/problem_builder/tests/integration/base_test.py b/problem_builder/tests/integration/base_test.py index a71240ec..78aad9f2 100644 --- a/problem_builder/tests/integration/base_test.py +++ b/problem_builder/tests/integration/base_test.py @@ -19,7 +19,7 @@ # import time -import mock +from unittest import mock from xblock.fields import String from xblockutils.base_test import SeleniumBaseTest, SeleniumXBlockTest from xblockutils.resources import ResourceLoader @@ -36,7 +36,7 @@ CORRECT, INCORRECT, PARTIAL = "correct", "incorrect", "partially-correct" -class PopupCheckMixin(object): +class PopupCheckMixin: """ Code used by MentoringBaseTest and MentoringAssessmentBaseTest """ @@ -89,7 +89,7 @@ def load_scenario(self, xml_file, params=None, load_immediately=True): Given the name of an XML file in the xml_templates folder, load it into the workbench. """ params = params or {} - scenario = loader.render_template("xml_templates/{}".format(xml_file), params) + scenario = loader.render_django_template("xml_templates/{}".format(xml_file), params) self.set_scenario_xml(scenario) if load_immediately: return self.go_to_view("student_view") @@ -182,7 +182,7 @@ def question_text(number): def load_assessment_scenario(self, xml_file, params=None): """ Loads an assessment scenario from an XML template """ params = params or {} - scenario = loader.render_template("xml_templates/{}".format(xml_file), params) + scenario = loader.render_django_template("xml_templates/{}".format(xml_file), params) self.set_scenario_xml(scenario) return self.go_to_assessment() @@ -190,7 +190,7 @@ def go_to_assessment(self): """ Navigates to assessment page """ mentoring = self.go_to_view("student_view") - class Namespace(object): + class Namespace: pass controls = Namespace() @@ -328,7 +328,7 @@ def _assert_checkmark(self, mentoring, result): self.assertEqual(len(mentoring.find_elements_by_css_selector(".submit .checkmark-{}".format(name))), count) -class GetChoices(object): +class GetChoices: """ Helper class for interacting with MCQ options """ def __init__(self, question, selector=".choices"): self._mcq = question.find_element_by_css_selector(selector) diff --git a/problem_builder/tests/integration/test_completion.py b/problem_builder/tests/integration/test_completion.py index 54cda865..040e30f2 100644 --- a/problem_builder/tests/integration/test_completion.py +++ b/problem_builder/tests/integration/test_completion.py @@ -28,7 +28,7 @@ # Classes ########################################################### -class CompletionBlockTestMixin(object): +class CompletionBlockTestMixin: """ Mixin for testing completion blocks. """ @@ -47,6 +47,7 @@ def completion_checkboxes(self): def expect_checkmarks_visible(self, first_visible, second_visible): first_checkmark, second_checkmark = self.checkmarks + time.sleep(3) self.assertEqual(first_checkmark.is_displayed(), first_visible) self.assertEqual(second_checkmark.is_displayed(), second_visible) diff --git a/problem_builder/tests/integration/test_dashboard.py b/problem_builder/tests/integration/test_dashboard.py index e78f32de..3533d710 100644 --- a/problem_builder/tests/integration/test_dashboard.py +++ b/problem_builder/tests/integration/test_dashboard.py @@ -21,13 +21,13 @@ from functools import wraps from textwrap import dedent -from mock import Mock, patch +from unittest.mock import Mock, patch from selenium.common.exceptions import NoSuchElementException from .base_test import ProblemBuilderBaseTest -class MockSubmissionsAPI(object): +class MockSubmissionsAPI: """ Mock the submissions API, since it's not available in the test environment. """ diff --git a/problem_builder/tests/integration/test_instructor_tool.py b/problem_builder/tests/integration/test_instructor_tool.py index 4fa3bdf0..78225208 100644 --- a/problem_builder/tests/integration/test_instructor_tool.py +++ b/problem_builder/tests/integration/test_instructor_tool.py @@ -6,14 +6,14 @@ import re import time -from mock import Mock, patch +from unittest.mock import Mock, patch from selenium.common.exceptions import NoSuchElementException from xblockutils.base_test import SeleniumXBlockTest from problem_builder.instructor_tool import PAGE_SIZE, InstructorToolBlock -class MockTasksModule(object): +class MockTasksModule: """Mock for the tasks module, which can only be meaningfully import in the LMS.""" def __init__(self, successful=True, display_data=[]): @@ -36,7 +36,7 @@ def __init__(self, successful=True, display_data=[]): self.export_data.delay.return_value = async_result -class MockInstructorTaskModelsModule(object): +class MockInstructorTaskModelsModule: def __init__(self): self.ReportStore = Mock() diff --git a/problem_builder/tests/integration/test_mentoring.py b/problem_builder/tests/integration/test_mentoring.py index 373f0f81..d53730af 100644 --- a/problem_builder/tests/integration/test_mentoring.py +++ b/problem_builder/tests/integration/test_mentoring.py @@ -18,7 +18,7 @@ # "AGPLv3". If not, see . # import ddt -import mock +from unittest import mock from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.support.ui import WebDriverWait diff --git a/problem_builder/tests/integration/test_slider.py b/problem_builder/tests/integration/test_slider.py index f8623ea3..39ee167a 100644 --- a/problem_builder/tests/integration/test_slider.py +++ b/problem_builder/tests/integration/test_slider.py @@ -26,7 +26,7 @@ # Classes ########################################################### -class SliderBlockTestMixins(object): +class SliderBlockTestMixins: """ Mixins for testing slider blocks. Assumes only one slider block is on the page. """ def get_slider_value(self): diff --git a/problem_builder/tests/integration/test_step_builder.py b/problem_builder/tests/integration/test_step_builder.py index 21f5dfaa..99c32435 100644 --- a/problem_builder/tests/integration/test_step_builder.py +++ b/problem_builder/tests/integration/test_step_builder.py @@ -1,7 +1,7 @@ import time from ddt import data, ddt, unpack -from mock import patch +from unittest.mock import patch from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.support.ui import WebDriverWait @@ -12,7 +12,7 @@ from .test_dashboard import MockSubmissionsAPI -class HTMLColors(object): +class HTMLColors: GREEN = 'rgb(0, 128, 0)' BLUE = 'rgb(0, 0, 255)' RED = 'rgb(255, 0, 0)' @@ -757,7 +757,7 @@ def submit_and_go_to_next_step(self, controls, last=False, no_questions=False): self.wait_until_disabled(controls.next_question) def plot_controls(self, step_builder): - class Namespace(object): + class Namespace: pass plot_controls = Namespace() @@ -769,7 +769,7 @@ class Namespace(object): return plot_controls def additional_plot_controls(self, step_builder): - class Namespace(object): + class Namespace: pass additional_plot_controls = Namespace() @@ -893,14 +893,14 @@ def check_overlays(self, step_builder, total_num_points, overlays): ] self.assertTrue(all(pc == overlay['point_color'] for pc in point_colors)) # Check tooltips for points - tooltips = set([ + tooltips = { point.get_attribute('data-tooltip') for point in points - ]) + } self.assertEquals(tooltips, set(overlay['tooltips'])) # Check positions - point_positions = set([ + point_positions = { (point.get_attribute('cx'), point.get_attribute('cy')) for point in points - ]) + } self.assertEquals(point_positions, set(overlay['positions'])) def test_plot(self): diff --git a/problem_builder/tests/integration/test_table.py b/problem_builder/tests/integration/test_table.py index f7be6948..14131e8e 100644 --- a/problem_builder/tests/integration/test_table.py +++ b/problem_builder/tests/integration/test_table.py @@ -20,7 +20,7 @@ # Imports ########################################################### -from mock import patch +from unittest.mock import patch from workbench.runtime import WorkbenchRuntime diff --git a/problem_builder/tests/integration/test_titles.py b/problem_builder/tests/integration/test_titles.py index 3083de88..3156fdd1 100644 --- a/problem_builder/tests/integration/test_titles.py +++ b/problem_builder/tests/integration/test_titles.py @@ -23,7 +23,7 @@ # Imports ########################################################### import ddt -from mock import patch +from unittest.mock import patch from xblockutils.base_test import SeleniumXBlockTest # Classes ########################################################### diff --git a/problem_builder/tests/unit/test_instructor_tool.py b/problem_builder/tests/unit/test_instructor_tool.py index 8d6648b4..098f3c41 100644 --- a/problem_builder/tests/unit/test_instructor_tool.py +++ b/problem_builder/tests/unit/test_instructor_tool.py @@ -4,7 +4,7 @@ import unittest import ddt -from mock import Mock, patch +from unittest.mock import Mock, patch from xblock.field_data import DictFieldData from problem_builder.instructor_tool import (COURSE_BLOCKS_API, @@ -57,9 +57,9 @@ def test_student_view_template_args(self): } with patch('problem_builder.instructor_tool.loader') as patched_loader: - patched_loader.render_template.return_value = u'' + patched_loader.render_django_template.return_value = u'' self.block.student_view() - patched_loader.render_template.assert_called_once_with('templates/html/instructor_tool.html', { + patched_loader.render_django_template.assert_called_once_with('templates/html/instructor_tool.html', { 'block_choices': block_choices, 'course_blocks_api': COURSE_BLOCKS_API, 'root_block_id': self.course_id, diff --git a/problem_builder/tests/unit/test_migration.py b/problem_builder/tests/unit/test_migration.py index 8202d172..cbabc56c 100644 --- a/problem_builder/tests/unit/test_migration.py +++ b/problem_builder/tests/unit/test_migration.py @@ -1,7 +1,7 @@ import copy import unittest -from mock import MagicMock, Mock +from unittest.mock import MagicMock, Mock from xblock.field_data import DictFieldData from problem_builder.mentoring import MentoringBlock diff --git a/problem_builder/tests/unit/test_mixins.py b/problem_builder/tests/unit/test_mixins.py index dc55e529..0d2d10af 100644 --- a/problem_builder/tests/unit/test_mixins.py +++ b/problem_builder/tests/unit/test_mixins.py @@ -3,7 +3,7 @@ from datetime import datetime import pytz -from mock import MagicMock, Mock +from unittest.mock import MagicMock, Mock from xblock.core import XBlock from xblock.field_data import DictFieldData from xblock.fields import Boolean, DateTime, Integer, Scope, String @@ -11,13 +11,13 @@ from problem_builder.mixins import StudentViewUserStateMixin -class NoUserStateFieldsMixin(object): +class NoUserStateFieldsMixin: scope_settings = String(name="Field1", scope=Scope.settings) scope_content = String(name="Field1", scope=Scope.content) user_state_summary = String(name="Not in the output", scope=Scope.user_state_summary) -class UserStateFieldsMixin(object): +class UserStateFieldsMixin: answer_1 = String(name="state1", scope=Scope.user_state) answer_2 = Boolean(name="state2", scope=Scope.user_state) @@ -28,7 +28,7 @@ class UserStateFieldsMixin(object): user_info_2 = DateTime(name="info2", scope=Scope.user_info) -class ChildrenMixin(object): +class ChildrenMixin: # overriding children for ease of testing _children = [] has_children = True diff --git a/problem_builder/tests/unit/test_models.py b/problem_builder/tests/unit/test_models.py index e4fd5773..90bcb5d8 100644 --- a/problem_builder/tests/unit/test_models.py +++ b/problem_builder/tests/unit/test_models.py @@ -2,7 +2,7 @@ Unit tests for models. """ from django.test import TestCase -from mock import MagicMock, PropertyMock +from unittest.mock import MagicMock, PropertyMock from problem_builder.models import Answer, delete_anonymous_user_answers diff --git a/problem_builder/tests/unit/test_problem_builder.py b/problem_builder/tests/unit/test_problem_builder.py index e2875fc4..5f38eb4c 100644 --- a/problem_builder/tests/unit/test_problem_builder.py +++ b/problem_builder/tests/unit/test_problem_builder.py @@ -2,8 +2,9 @@ from random import random import ddt -from mock import MagicMock, Mock, PropertyMock, patch +from unittest.mock import MagicMock, Mock, PropertyMock, patch from xblock.field_data import DictFieldData +from xblock.runtime import NullI18nService from problem_builder.answer import AnswerRecapBlock from problem_builder.mcq import MCQBlock @@ -56,6 +57,7 @@ def test_sends_progress_event_when_rendered_student_view_with_display_submit_fal with patch.object(block, 'runtime') as patched_runtime: patched_runtime.publish = Mock() + patched_runtime.service = lambda _, service: NullI18nService() if service == 'i18n' else MagicMock() block.student_view(context={}) @@ -68,6 +70,7 @@ def test_does_not_send_progress_event_when_rendered_student_view_with_display_su with patch.object(block, 'runtime') as patched_runtime: patched_runtime.publish = Mock() + patched_runtime.service = lambda _, service: NullI18nService() if service == 'i18n' else MagicMock() block.student_view(context={}) @@ -95,7 +98,7 @@ def test_does_not_crash_when_get_child_is_broken(self): with patch.object(block, 'runtime') as patched_runtime: patched_runtime.publish = Mock() - patched_runtime.service().ugettext = lambda str: str + patched_runtime.service = lambda _, service: NullI18nService() if service == 'i18n' else MagicMock() patched_runtime.get_block = lambda block_id: None patched_runtime.load_block_type = lambda block_id: Mock diff --git a/problem_builder/tests/unit/test_step.py b/problem_builder/tests/unit/test_step.py index b3bb8695..0e86f4f8 100644 --- a/problem_builder/tests/unit/test_step.py +++ b/problem_builder/tests/unit/test_step.py @@ -1,6 +1,6 @@ import unittest -from mock import Mock +from unittest.mock import Mock from xblock.field_data import DictFieldData from problem_builder.mixins import QuestionMixin, StepParentMixin @@ -38,7 +38,7 @@ def __init__(self): pass -class NotAStep(object): +class NotAStep: pass diff --git a/problem_builder/tests/unit/test_step_builder.py b/problem_builder/tests/unit/test_step_builder.py index 69f3d634..bb053bf0 100644 --- a/problem_builder/tests/unit/test_step_builder.py +++ b/problem_builder/tests/unit/test_step_builder.py @@ -1,6 +1,6 @@ import unittest -from mock import Mock +from unittest.mock import Mock from xblock.field_data import DictFieldData from problem_builder.mentoring import MentoringWithExplicitStepsBlock diff --git a/problem_builder/tests/unit/test_swipe.py b/problem_builder/tests/unit/test_swipe.py index 2ed3d37e..d48d5974 100644 --- a/problem_builder/tests/unit/test_swipe.py +++ b/problem_builder/tests/unit/test_swipe.py @@ -1,7 +1,7 @@ import unittest import ddt -from mock import Mock +from unittest.mock import Mock from xblock.field_data import DictFieldData from problem_builder.swipe import SwipeBlock diff --git a/problem_builder/tests/unit/utils.py b/problem_builder/tests/unit/utils.py index 69263e9d..6fdfda95 100644 --- a/problem_builder/tests/unit/utils.py +++ b/problem_builder/tests/unit/utils.py @@ -4,11 +4,11 @@ import json from datetime import date, datetime -from mock import MagicMock, Mock, patch +from unittest.mock import MagicMock, Mock, patch from xblock.field_data import DictFieldData -class ScoresTestMixin(object): +class ScoresTestMixin: """ Mixin for tests that involve scores (grades) """ @@ -23,7 +23,7 @@ def assert_produces_scores(self, block): self.assertIsInstance(block.max_score(), (int, float)) -class BlockWithChildrenTestMixin(object): +class BlockWithChildrenTestMixin: """ Mixin for tests targeting blocks that contain nested child blocks. """ diff --git a/problem_builder/tip.py b/problem_builder/tip.py index b33a0557..858d44af 100644 --- a/problem_builder/tip.py +++ b/problem_builder/tip.py @@ -89,7 +89,7 @@ def display_name_with_default(self): def mentoring_view(self, context=None): """ Render this XBlock within a mentoring block. """ - html = loader.render_template("templates/html/tip.html", { + html = loader.render_django_template("templates/html/tip.html", { 'content': self.content, 'width': self.width, 'height': self.height, diff --git a/problem_builder/utils.py b/problem_builder/utils.py index ebff0d61..cade2132 100644 --- a/problem_builder/utils.py +++ b/problem_builder/utils.py @@ -15,7 +15,7 @@ def ngettext_fallback(text_singular, text_plural, number): return text_plural -class DummyTranslationService(object): +class DummyTranslationService: """ Dummy drop-in replacement for i18n XBlock service """ @@ -24,7 +24,7 @@ class DummyTranslationService(object): ngettext = ngettext_fallback -class I18NService(object): +class I18NService: """ Add i18n_service attribute to XBlocks """ diff --git a/problem_builder/v1/xml_changes.py b/problem_builder/v1/xml_changes.py index 743011c1..5356483a 100644 --- a/problem_builder/v1/xml_changes.py +++ b/problem_builder/v1/xml_changes.py @@ -27,7 +27,7 @@ from lxml import etree -class Change(object): +class Change: @staticmethod def applies_to(node): """ diff --git a/pylintrc b/pylintrc index d371e599..53887a89 100644 --- a/pylintrc +++ b/pylintrc @@ -362,7 +362,8 @@ disable=blacklisted-name, xreadlines-attribute, deprecated-sys-function, exception-escape, - comprehension-escape + comprehension-escape, + import-outside-toplevel # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/requirements-dev.txt b/requirements-dev.txt index 517e5c11..7c741288 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,9 @@ # Internationalization and Localization requirements --e git://github.com/edx/xblock-sdk.git@v0.1.4#egg=xblock-sdk==v0.1.4 -Django==1.11.23 +-e git://github.com/edx/xblock-sdk.git@v0.1.7#egg=xblock-sdk==v0.1.7 +Django~=2.2.10 django-statici18n==1.8.2 transifex-client==0.12.1 -edx-i18n-tools==0.4.7 +edx-i18n-tools==0.5.0 pycodestyle==2.4.0 pylint==0.28.0 -django-babel-underscore==0.5.2 +git+https://github.com/edx/django-babel-underscore.git@37705f7377a4d0a4e673f1431895ce28a8860cd7#egg=django-babel-underscore==0.6.0 diff --git a/requirements.txt b/requirements.txt index 62959ce4..89d4ce10 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,6 @@ XBlock>=1.2 ddt -mock -unicodecsv==0.9.4 +unicodecsv==0.11.0 edx-opaque-keys>=0.4 --e git+https://github.com/edx/xblock-utils.git@v1.2.0#egg=xblock-utils +-e git+https://github.com/edx/xblock-utils.git@2.0.0#egg=xblock-utils -e . diff --git a/setup.py b/setup.py index 8a3a31ee..1dec85bc 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ # Constants ######################################################### -VERSION = '3.4.14' +VERSION = '4.0.0' # Functions ######################################################### diff --git a/test_requirements.in b/test_requirements.in index 24cb8291..ab4750cd 100644 --- a/test_requirements.in +++ b/test_requirements.in @@ -1,20 +1,21 @@ -e xblock-sdk bok_choy==0.7.1 ddt -django_nose>=1.4.4 +django_nose>=1.4.6 -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock --e git+https://github.com/edx/django-pyfs.git@1.0.3#egg=django-pyfs==1.0.3 --e git+https://github.com/edx/xblock-utils.git@v1.2.2#egg=xblock-utils +-e git+https://github.com/edx/django-pyfs.git@2.1#egg=django-pyfs==2.1 +-e git+https://github.com/edx/xblock-utils.git@2.0.0#egg=xblock-utils lazy lxml mock selenium==3.4.1 webob XBlock>=1.2 -Django>=1.11,<2.0 +Django~=2.2.10 pytest -coverage<5 pylint pycodestyle +django-mysql +mysqlclient -r xblock-sdk/requirements/base.txt -r xblock-sdk/requirements/test.txt diff --git a/test_requirements.txt b/test_requirements.txt index f3107f2b..b1eada07 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -4,84 +4,84 @@ # # pip-compile --output-file=test_requirements.txt test_requirements.in # --e git+https://github.com/edx/acid-block.git@98aecba94ecbfa934e2d00262741c0ea9f557fc9#egg=acid-xblock --e git+https://github.com/edx/django-pyfs.git@1.0.3#egg=django-pyfs==1.0.3 --e xblock-sdk --e git+https://github.com/edx/xblock-utils.git@v1.2.2#egg=xblock-utils -appdirs==1.4.3 -astroid==1.6.6 # via pylint -atomicwrites==1.3.0 -attrs==19.2.0 -backports.functools-lru-cache==1.6.1 # via astroid, isort, pylint -backports.os==0.1.1 -binaryornot==0.4.4 -bok_choy==0.7.1 -boto3==1.4.8 -boto==2.39.0 -botocore==1.8.50 -chardet==3.0.4 -configparser==4.0.2 -contextlib2==0.6.0 -cookiecutter==0.9.0 -coverage==4.5.4 -ddt==1.2.1 -django-nose==1.4.6 -django==1.11.25 -docutils==0.15.2 -enum34==1.1.6 -filelock==3.0.12 -fs-s3fs==0.1.5 -fs==2.0.27 -funcsigs==1.0.2 -future==0.17.1 -futures==3.3.0 ; python_version == "2.7" -importlib-metadata==0.23 +-e git+https://github.com/edx/acid-block.git@98aecba94ecbfa934e2d00262741c0ea9f557fc9#egg=acid-xblock # via -r xblock-sdk/requirements/test.txt +-e git+https://github.com/edx/django-pyfs.git@2.1#egg=django-pyfs==2.1 # via -r test_requirements.in +-e xblock-sdk # via -r test_requirements.in +-e git+https://github.com/edx/xblock-utils.git@2.0.0#egg=xblock-utils # via -r test_requirements.in +appdirs==1.4.3 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, fs, virtualenv +astroid==2.3.3 # via pylint +atomicwrites==1.3.0 # via -r xblock-sdk/requirements/test.txt, pytest +attrs==19.3.0 # via -r xblock-sdk/requirements/test.txt, pytest +binaryornot==0.4.4 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, cookiecutter +bok_choy==0.7.1 # via -r test_requirements.in, -r xblock-sdk/requirements/test.txt +boto3==1.12.9 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, fs-s3fs +boto==2.39.0 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt +botocore==1.15.9 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, boto3, s3transfer +certifi==2019.11.28 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, requests +chardet==3.0.4 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, binaryornot, requests +cookiecutter==0.9.0 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt +coverage==5.0.3 # via -r xblock-sdk/requirements/test.txt, pytest-cov +ddt==1.2.2 # via -r test_requirements.in, -r xblock-sdk/requirements/test.txt +distlib==0.3.0 # via -r xblock-sdk/requirements/test.txt, virtualenv +django-mysql==2.4.1 # via -r test_requirements.in +django-nose==1.4.6 # via -r test_requirements.in +django==2.2.10 # via -r test_requirements.in, -r xblock-sdk/requirements/base.txt, django-mysql, django-pyfs, xblock-sdk +docutils==0.15.2 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, botocore +filelock==3.0.12 # via -r xblock-sdk/requirements/test.txt, tox, virtualenv +fs-s3fs==0.1.8 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, django-pyfs +fs==2.0.27 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, django-pyfs, fs-s3fs, xblock +idna==2.8 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, requests +importlib-metadata==1.5.0 # via -r xblock-sdk/requirements/test.txt, pluggy, pytest, tox, virtualenv +importlib-resources==1.0.2 # via -r xblock-sdk/requirements/test.txt, virtualenv isort==4.3.21 # via pylint -jinja2==2.10.1 -jmespath==0.9.4 +jinja2==2.11.1 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, cookiecutter +jmespath==0.9.5 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, boto3, botocore lazy-object-proxy==1.4.3 # via astroid -lazy==1.1 -lxml==3.8.0 -mako==1.1.0 -markupsafe==1.1.1 +lazy==1.1 # via -r test_requirements.in, -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, acid-xblock, bok-choy +lxml==3.8.0 # via -r test_requirements.in, -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, xblock +mako==1.1.1 # via -r xblock-sdk/requirements/test.txt, acid-xblock, xblock-utils +markupsafe==1.1.1 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, jinja2, mako, xblock mccabe==0.6.1 # via pylint -mock==3.0.5 -more-itertools==5.0.0 -needle==0.5.0 -nose==1.3.7 -packaging==19.2 -pathlib2==2.3.5 -pillow==6.1.0 -pluggy==0.13.0 -py==1.8.0 -pycodestyle==2.5.0 -pylint==1.9.5 -pyparsing==2.4.2 -pypng==0.0.20 -pytest-cov==2.7.1 -pytest-django==3.5.1 -pytest==4.6.5 -python-dateutil==2.8.0 -pytz==2019.2 -pyyaml==5.1.2 -requests==2.9.1 -s3transfer==0.1.13 -scandir==1.10.0 -selenium==3.4.1 -simplejson==3.16.0 -singledispatch==3.4.0.3 # via astroid, pylint -six==1.10.0 -toml==0.10.0 -tox-battery==0.5.1 -tox==3.14.0 -typing==3.7.4.1 -virtualenv==16.7.5 -wcwidth==0.1.7 -web-fragments==0.3.0 -webob==1.8.5 +mock==3.0.5 # via -r test_requirements.in, -r xblock-sdk/requirements/test.txt +more-itertools==5.0.0 # via -r xblock-sdk/requirements/test.txt, pytest +mysqlclient==1.4.6 # via -r test_requirements.in +needle==0.5.0 # via -r xblock-sdk/requirements/test.txt, bok-choy +nose==1.3.7 # via -r xblock-sdk/requirements/test.txt, django-nose, needle +packaging==20.1 # via -r xblock-sdk/requirements/test.txt, pytest, tox +pathlib2==2.3.5 # via -r xblock-sdk/requirements/test.txt, pytest +pillow==6.2.2 # via -r xblock-sdk/requirements/test.txt, needle +pluggy==0.13.1 # via -r xblock-sdk/requirements/test.txt, pytest, tox +py==1.8.1 # via -r xblock-sdk/requirements/test.txt, pytest, tox +pycodestyle==2.5.0 # via -r test_requirements.in +pylint==2.4.4 # via -r test_requirements.in +pyparsing==2.4.6 # via -r xblock-sdk/requirements/test.txt, packaging +pypng==0.0.20 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt +pytest-cov==2.8.1 # via -r xblock-sdk/requirements/test.txt +pytest-django==3.8.0 # via -r xblock-sdk/requirements/test.txt +pytest-rerunfailures==8.0 # via -r xblock-sdk/requirements/test.txt +pytest==4.6.9 # via -r test_requirements.in, -r xblock-sdk/requirements/test.txt, pytest-cov, pytest-django, pytest-rerunfailures +python-dateutil==2.8.1 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, botocore, xblock +pytz==2019.3 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, django, fs, xblock +pyyaml==5.3 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, cookiecutter, xblock +requests==2.22.0 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt +s3transfer==0.3.3 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, boto3 +selenium==3.4.1 # via -r test_requirements.in, -r xblock-sdk/requirements/test.txt, bok-choy, needle +simplejson==3.17.0 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, xblock-utils +six==1.14.0 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, astroid, bok-choy, django-pyfs, fs, fs-s3fs, mock, more-itertools, packaging, pathlib2, pytest, python-dateutil, tox, virtualenv, xblock +sqlparse==0.3.0 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, django +toml==0.10.0 # via -r xblock-sdk/requirements/test.txt, tox +tox-battery==0.5.2 # via -r xblock-sdk/requirements/test.txt +tox==3.14.5 # via -r xblock-sdk/requirements/test.txt, tox-battery +typed-ast==1.4.1 # via astroid +typing==3.7.4.1 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, fs +urllib3==1.25.8 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, botocore, requests +virtualenv==20.0.7 # via -r xblock-sdk/requirements/test.txt, tox +wcwidth==0.1.8 # via -r xblock-sdk/requirements/test.txt, pytest +web-fragments==0.3.1 # via -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, xblock, xblock-utils +webob==1.8.6 # via -r test_requirements.in, -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, xblock wrapt==1.11.2 # via astroid -xblock==1.2.6 -zipp==0.6.0 +xblock==1.2.9 # via -r test_requirements.in, -r xblock-sdk/requirements/base.txt, -r xblock-sdk/requirements/test.txt, acid-xblock, xblock-utils +zipp==1.2.0 # via -r xblock-sdk/requirements/test.txt, importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/xblock-sdk b/xblock-sdk index 331e50be..e3d8f2a5 160000 --- a/xblock-sdk +++ b/xblock-sdk @@ -1 +1 @@ -Subproject commit 331e50bed2a3c9014d998cc4428e92bf658baf8d +Subproject commit e3d8f2a505660bc5c3710c955576a5fefdcc4eaf