* feat: library unit sync * feat: create component link only for component xblocks * feat: container link model * feat: update downstream api views * feat: delete extra components in container on sync (not working) * fix: duplicate definitions of LibraryXBlockMetadata * test: add a new integration test suite for syncing * feat: partially implement container+child syncing * fix: blockserializer wasn't always serializing all HTML block fields * feat: handle reorder, addition and deletion of components in sync Updates children components of unit in course based on upstream unit, deletes removed component, adds new ones and updates order as per upstream. * feat: return unit upstreamInfo and disallow edits to units in courses that are sourced from a library (#773) * feat: Add upstream_info to unit * feat: disallow edits to units in courses that are sourced from a library (#774) --------- Co-authored-by: Jillian Vogel <jill@opencraft.com> Co-authored-by: Rômulo Penido <romulo.penido@gmail.com> * docs: capitalization of XBlock Co-authored-by: David Ormsbee <dave@axim.org> * refactor: (minor) change python property name to reflect type better * fix: lots of "Tried to inspect a missing...upstream link" warnings when viewing a unit in Studio * docs: mention potential REST API for future refactor * fix: check if upstream actually exists before making unit read-only * chore: fix camel-case var * fix: test failure when mocked XBlock doesn't have UpstreamSyncMixin --------- Co-authored-by: Braden MacDonald <braden@opencraft.com> Co-authored-by: Chris Chávez <xnpiochv@gmail.com> Co-authored-by: Jillian Vogel <jill@opencraft.com> Co-authored-by: Rômulo Penido <romulo.penido@gmail.com> Co-authored-by: Braden MacDonald <mail@bradenm.com> Co-authored-by: David Ormsbee <dave@axim.org>
231 lines
12 KiB
INI
231 lines
12 KiB
INI
[tool:pytest]
|
|
# Note: The first file of settings found is used, there is no combining, so
|
|
# this file is only used for tests that don't find a pytest.ini file first.
|
|
# Details at https://docs.pytest.org/en/latest/reference/customize.html
|
|
|
|
DJANGO_SETTINGS_MODULE = lms.envs.test
|
|
addopts = --nomigrations --reuse-db --durations=20 --json-report --json-report-omit keywords streams collectors log traceback tests --json-report-file=none
|
|
# Enable default handling for all warnings, including those that are ignored by default;
|
|
# but hide rate-limit warnings (because we deliberately don't throttle test user logins)
|
|
# and field_data deprecation warnings (because fixing them requires a major low-priority refactoring)
|
|
filterwarnings =
|
|
default
|
|
ignore:No request passed to the backend, unable to rate-limit:UserWarning
|
|
ignore::xblock.exceptions.FieldDataDeprecationWarning
|
|
# Remove default_app_config warning after updating Django to 4.2
|
|
ignore:.*You can remove default_app_config.*:PendingDeprecationWarning
|
|
ignore:Instead access HTTPResponse.headers directly.*:DeprecationWarning:elasticsearch
|
|
# ABC deprecation Warning comes from libsass
|
|
ignore:Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated.*:DeprecationWarning:sass
|
|
ignore:'etree' is deprecated. Use 'xml.etree.ElementTree' instead.:DeprecationWarning:wiki
|
|
|
|
junit_family = xunit2
|
|
norecursedirs = .* *.egg build conf dist node_modules test_root cms/envs lms/envs
|
|
python_classes =
|
|
python_files = tests.py test_*.py tests_*.py *_tests.py __init__.py
|
|
|
|
[pycodestyle]
|
|
# error codes: https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes
|
|
# E501: line too long
|
|
# E265: block comment should start with '# '
|
|
# We ignore this because pep8 used to erroneously lump E266 into it also.
|
|
# We should probably fix these now.
|
|
# E266: too many leading '#' for block comment
|
|
# We have lots of comments that look like "##### HEADING #####" which violate
|
|
# this rule, because they don't have a space after the first #. However,
|
|
# they're still perfectly reasonable comments, so we disable this rule.
|
|
# W602: deprecated form of raising exception
|
|
# We do this in a few places to modify the exception message while preserving
|
|
# the traceback. See this blog post for more info:
|
|
# http://nedbatchelder.com/blog/200711/rethrowing_exceptions_in_python.html
|
|
# It's a little unusual, but we have good reasons for doing so, so we disable
|
|
# this rule.
|
|
# E305,E402,E722,E731,E741,E743,W503,W504: errors and warnings added since pep8/pycodestyle
|
|
# 1.5.7 that we haven't cleaned up yet
|
|
ignore=E265,E266,E305,E402,E501,E722,E731,E741,E743,W503,W504,W602
|
|
exclude=migrations,.git,.pycharm_helpers,.tox,test_root/staticfiles,node_modules
|
|
|
|
[isort]
|
|
indent=' '
|
|
line_length=120
|
|
multi_line_output=3
|
|
skip=
|
|
envs
|
|
migrations
|
|
|
|
[importlinter]
|
|
root_packages =
|
|
lms
|
|
cms
|
|
openedx
|
|
openedx_learning
|
|
include_external_packages = True
|
|
contract_types =
|
|
# Our custom contract which checks that we're only importing from 'api.py'
|
|
# for participating packages.
|
|
isolated_apps: openedx.testing.importlinter.isolated_apps_contract.IsolatedAppsContract
|
|
|
|
[importlinter:contract:1]
|
|
name = lms and cms are independent
|
|
type = independence
|
|
modules =
|
|
lms
|
|
cms
|
|
ignore_imports =
|
|
############################################################################
|
|
# lms side imports that we are ignoring for now
|
|
lms.djangoapps.course_home_api.outline.tests.test_view -> cms.djangoapps.contentstore.outlines
|
|
lms.djangoapps.course_home_api.tests.utils -> cms.djangoapps.contentstore.outlines
|
|
# lms.djangoapps.instructor.tests.test_api & lms.djangoapps.instructor.tests.test_tools
|
|
# -> openedx.core.djangoapps.course_date_signals.handlers
|
|
# -> cms.djangoapps.contentstore.config.waffle
|
|
openedx.core.djangoapps.course_date_signals.handlers -> cms.djangoapps.contentstore.config.waffle
|
|
############################################################################
|
|
# cms side imports that we are ignoring for now
|
|
cms.djangoapps.contentstore.views.tests.test_block -> lms.djangoapps.lms_xblock.mixin
|
|
cms.envs.common -> lms.envs.common
|
|
cms.djangoapps.contentstore.signals.handlers -> lms.djangoapps.grades.api
|
|
cms.djangoapps.contentstore.course_group_config -> lms.lib.utils
|
|
cms.djangoapps.contentstore.views.preview -> lms.djangoapps.lms_xblock.field_data
|
|
cms.envs.common -> lms.djangoapps.lms_xblock.mixin
|
|
cms.envs.test -> lms.envs.test
|
|
# cms.djangoapps.contentstore.views.tests.test_group_configurations
|
|
# -> openedx.features.content_type_gating.helpers
|
|
# -> lms.djangoapps.courseware.masquerade
|
|
openedx.features.content_type_gating.helpers -> lms.djangoapps.courseware.masquerade
|
|
# cms.djangoapps.contentstore.utils
|
|
# -> openedx.core.djangoapps.django_comment_common.models
|
|
# -> openedx.core.djangoapps.course_groups.cohorts
|
|
# -> lms.djangoapps.courseware.courses
|
|
openedx.core.djangoapps.course_groups.cohorts -> lms.djangoapps.courseware.courses
|
|
# cms.djangoapps.models.settings.course_metadata
|
|
# -> openedx.features.course_experience
|
|
# -> openedx.features.course_experience.url_helpers
|
|
# -> lms.djangoapps.courseware.toggles
|
|
openedx.features.course_experience.url_helpers -> lms.djangoapps.courseware.toggles
|
|
# cms.djangoapps.contentstore.[various]
|
|
# -> openedx.features.content_type_gating.partitions
|
|
# -> lms.djangoapps.commerce.utils
|
|
openedx.features.content_type_gating.partitions -> lms.djangoapps.commerce.utils
|
|
# cms.djangoapps.contentstore.course_group_config
|
|
# -> openedx.core.djangoapps.course_groups.partition_scheme
|
|
# -> lms.djangoapps.courseware.masquerade
|
|
openedx.core.djangoapps.course_groups.partition_scheme -> lms.djangoapps.courseware.masquerade
|
|
# cms.djangoapps.contentstore.[various]
|
|
# -> openedx.core.djangoapps.content.course_overviews.models
|
|
# -> lms.djangoapps.ccx.utils
|
|
# & lms.djangoapps.certificates.api
|
|
# & lms.djangoapps.discussion.django_comment_client
|
|
openedx.core.djangoapps.content.course_overviews.models -> lms.djangoapps.*.*
|
|
# cms.djangoapps.export_course_metadata.tasks
|
|
# -> openedx.core.djangoapps.schedules.content_highlights
|
|
# -> lms.djangoapps.courseware.block_render & lms.djangoapps.courseware.model_data
|
|
openedx.core.djangoapps.content_libraries.* -> lms.djangoapps.*.*
|
|
# cms.djangoapps.contentstore.tasks -> openedx.core.djangoapps.content_libraries.[various]
|
|
# -> lms.djangoapps.grades.api
|
|
openedx.core.djangoapps.xblock.*.* -> lms.djangoapps.*.*
|
|
# cms.djangoapps.contentstore.tasks -> openedx.core.djangoapps.content_libraries.[various] -> openedx.core.djangoapps.xblock.[various]
|
|
# -> lms.djangoapps.courseware & lms.djangoapps.courseware.grades
|
|
openedx.core.djangoapps.schedules.content_highlights -> lms.djangoapps.courseware.*
|
|
# cms.djangoapps.contentstore.[various]
|
|
# -> openedx.core.lib.gating.api
|
|
# -> lms.djangoapps.course_blocks.api & lms.djangoapps.courseware.access & lms.djangoapps.grades.api
|
|
openedx.core.lib.gating.api -> lms.djangoapps.*.*
|
|
# cms.djangoapps.contentstore.[various]
|
|
# -> openedx.features.content_type_gating.partitions
|
|
# -> openedx.features.discounts.utils
|
|
# -> lms.djangoapps.courseware.utils & lms.djangoapps.experiments.models
|
|
openedx.features.discounts.utils -> lms.djangoapps.courseware.utils
|
|
openedx.features.discounts.utils -> lms.djangoapps.experiments.models
|
|
# cms.djangoapps.contentstore.signals.handlers
|
|
# -> openedx.core.djangoapps.discussions.tasks
|
|
# -> openedx.core.djangoapps.discussions.utils
|
|
# -> lms.djangoapps.courseware.access
|
|
openedx.core.djangoapps.discussions.utils -> lms.djangoapps.courseware.access
|
|
# cms.djangoapps.contentstore.[various]
|
|
# -> openedx.features.content_type_gating.partitions
|
|
# -> openedx.features.discounts.utils
|
|
# -> openedx.features.discounts.applicability
|
|
# -> lms.djangoapps.courseware.toggles
|
|
# & lms.djangoapps.courseware.utils
|
|
# & lms.djangoapps.experiments.models
|
|
# & lms.djangoapps.experiments.stable_bucketing
|
|
openedx.features.discounts.applicability -> lms.djangoapps.courseware.*
|
|
openedx.features.discounts.applicability -> lms.djangoapps.experiments.*
|
|
# cms.djangoapps.contentstore.[various]
|
|
# -> openedx.core.djangoapps.content.learning_sequences.api
|
|
# -> openedx.core.djangoapps.content.learning_sequences.api.outlines
|
|
# -> openedx.core.djangoapps.content.learning_sequences.api.permissions
|
|
# -> lms.djangoapps.courseware.access
|
|
openedx.core.djangoapps.content.learning_sequences.api.permissions -> lms.djangoapps.courseware.access
|
|
# cms.djangoapps.contentstore.[various]
|
|
# -> openedx.features.content_type_gating.partitions
|
|
# -> openedx.features.discounts.utils
|
|
# -> openedx.features.discounts.applicability
|
|
# -> openedx.features.enterprise_support.utils
|
|
openedx.features.enterprise_support.utils -> lms.djangoapps.branding.api
|
|
cms.djangoapps.contentstore.rest_api.v1.views.settings -> lms.djangoapps.certificates.api
|
|
|
|
|
|
[importlinter:contract:2]
|
|
name = Do not depend on non-public API of isolated apps.
|
|
type = isolated_apps
|
|
isolated_apps =
|
|
openedx.core.djangoapps.agreements
|
|
openedx.core.djangoapps.bookmarks
|
|
openedx.core.djangoapps.content_libraries
|
|
openedx.core.djangoapps.content_staging
|
|
openedx.core.djangoapps.olx_rest_api
|
|
openedx.core.djangoapps.xblock
|
|
openedx.core.lib.xblock_serializer
|
|
allowed_modules =
|
|
# Only imports from api.py and data.py are allowed elsewhere in the code
|
|
# See https://open-edx-proposals.readthedocs.io/en/latest/best-practices/oep-0049-django-app-patterns.html#api-py
|
|
api
|
|
data
|
|
tests
|
|
|
|
[importlinter:contract:3]
|
|
name = Do not import apps from openedx-learning (only import from openedx_learning.api.* and openedx_learning.lib.*).
|
|
type = forbidden
|
|
source_modules =
|
|
cms
|
|
lms
|
|
openedx
|
|
forbidden_modules =
|
|
openedx_learning.apps
|
|
allow_indirect_imports = True
|
|
|
|
[importlinter:contract:4]
|
|
name = Low-level apps should not depend on high-level apps
|
|
type = layers
|
|
layers =
|
|
# Layers from high-level to low-level. Imports should only occur from higher to lower.
|
|
cms.lib.xblock.upstream_sync | openedx.core.djangoapps.content.search | openedx.core.djangoapps.olx_rest_api
|
|
openedx.core.djangoapps.content_libraries
|
|
openedx.core.djangoapps.content_staging
|
|
openedx.core.djangoapps.xblock
|
|
openedx.core.lib.xblock_serializer
|
|
openedx.core.djangoapps.content_tagging
|
|
ignore_imports =
|
|
# Test code can break these layering rules
|
|
**.tests.** -> **
|
|
|
|
# FIXME: the exceptions below are from before we added this import linting rule. Should refactor to eliminate them.
|
|
# In particular, the contentstore.helpers module is too big and has too many imports - split it up?
|
|
|
|
# The CSV export hard-codes support for courses and libraries. Refactor to do something like learning_context.get_children()
|
|
openedx.core.djangoapps.content_tagging.helpers.objecttag_export_helpers -> openedx.core.djangoapps.content_libraries.api
|
|
# The permissions checking code for tagging requires libraries model data to get all the orgs that a user is using:
|
|
openedx.core.djangoapps.content_tagging.utils -> openedx.core.djangoapps.content_libraries.api
|
|
# Content staging POST to clipboard API uses libraries APIs. We're working on moving this code to content_libraries
|
|
openedx.core.djangoapps.content_staging.views -> openedx.core.djangoapps.content_libraries.api
|
|
# content_staging.serializers imports contentstore.helpers which imports contentstore.utils which imports the libraries API.
|
|
openedx.core.djangoapps.content_staging.serializers -> cms.djangoapps.contentstore.helpers
|
|
# content_libraries.rest_api.libraries imports cms.djangoapps.contentstore.views.course which imports
|
|
# contentstore.toggles which imports djangoapps.content.search.api
|
|
openedx.core.djangoapps.content_libraries.rest_api.libraries -> cms.djangoapps.contentstore.views.course
|
|
# Content libraries imports contentstore.helpers which imports upstream_sync
|
|
openedx.core.djangoapps.content_libraries.api.blocks -> cms.djangoapps.contentstore.helpers
|
|
openedx.core.djangoapps.content_libraries.api.libraries -> cms.djangoapps.contentstore.helpers
|