learningequality / kolibri

Kolibri Learning Platform: the offline app for universal education
https://learningequality.org/kolibri/
MIT License
809 stars 682 forks source link

'database is locked' error while import/exporting facility and trying to view device info page #7125

Closed indirectlylit closed 4 years ago

indirectlylit commented 4 years ago

Observed behavior

While running facility import or export, trying to access the device info page throws a 500 error:

image

{
  "data": "OperationalError at /api/device/deviceinfo/\ndatabase is locked\n\nRequest Method: GET\nRequest URL: http://localhost:8000/api/device/deviceinfo/?1592863732768=1592863732768\nDjango Version: 1.11.29\nPython Executable: /Users/d/.pyenv/versions/3.7.6/bin/python3.7\nPython Version: 3.7.6\nPython Path: ['/Users/d/Projects/le/develop/kolibri/dist', '/Users/d/.pyenv/versions/3.7.6/bin', '/Users/d/.pyenv/versions/3.7.6/lib/python37.zip', '/Users/d/.pyenv/versions/3.7.6/lib/python3.7', '/Users/d/.pyenv/versions/3.7.6/lib/python3.7/lib-dynload', '/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages', '/Users/d/Projects/le/perseus-plugin', '/Users/d/Projects/le/develop']\nServer time: Mon, 22 Jun 2020 15:08:53 -0700\nInstalled Applications:\n['kolibri.core',\n 'django.contrib.admin',\n 'django.contrib.auth',\n 'django.contrib.contenttypes',\n 'django.contrib.sessions',\n 'django.contrib.messages',\n 'django.contrib.staticfiles',\n 'django_filters',\n 'kolibri.core.auth.apps.KolibriAuthConfig',\n 'kolibri.core.content',\n 'kolibri.core.logger',\n 'kolibri.core.notifications.apps.KolibriNotificationsConfig',\n 'kolibri.core.tasks.apps.KolibriTasksConfig',\n 'kolibri.core.deviceadmin',\n 'kolibri.core.webpack',\n 'kolibri.core.exams',\n 'kolibri.core.device',\n 'kolibri.core.discovery',\n 'kolibri.core.lessons',\n 'kolibri.core.analytics',\n 'rest_framework',\n 'django_js_reverse',\n 'jsonfield',\n 'morango',\n <AppConfig: kolibri.plugins.html5_viewer>,\n <AppConfig: kolibri.plugins.setup_wizard>,\n <AppConfig: kolibri_exercise_perseus_plugin>,\n <AppConfig: kolibri.plugins.learn>,\n <AppConfig: kolibri.plugins.slideshow_viewer>,\n <AppConfig: kolibri.plugins.facility>,\n <AppConfig: kolibri.plugins.user>,\n <AppConfig: kolibri.plugins.device>,\n <AppConfig: kolibri.plugins.epub_viewer>,\n <AppConfig: kolibri.plugins.pdf_viewer>,\n <AppConfig: kolibri.plugins.media_player>,\n <AppConfig: kolibri.plugins.coach>,\n <AppConfig: kolibri.plugins.default_theme>,\n 'drf_yasg']\nInstalled Middleware:\n['kolibri.core.analytics.middleware.cherrypy_access_log_middleware',\n 'kolibri.core.device.middleware.ProvisioningErrorHandler',\n 'django.middleware.cache.UpdateCacheMiddleware',\n 'kolibri.core.analytics.middleware.MetricsMiddleware',\n 'django.contrib.sessions.middleware.SessionMiddleware',\n 'kolibri.core.device.middleware.KolibriLocaleMiddleware',\n 'django.middleware.common.CommonMiddleware',\n 'django.middleware.csrf.CsrfViewMiddleware',\n 'kolibri.core.auth.middleware.CustomAuthenticationMiddleware',\n 'django.contrib.messages.middleware.MessageMiddleware',\n 'django.middleware.clickjacking.XFrameOptionsMiddleware',\n 'django.middleware.security.SecurityMiddleware',\n 'django.middleware.cache.FetchFromCacheMiddleware',\n 'kolibri.core.webpack.middleware.WebpackErrorHandler']\n\n\nTraceback:  \n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py\" in execute\n  64.                 return self.cursor.execute(sql, params)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py\" in execute\n  328.         return Database.Cursor.execute(self, query, params)\n  \n    \n      The above exception (database is locked) was the direct cause of the following exception:\n    \n  \n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/core/handlers/exception.py\" in inner\n  41.             response = get_response(request)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/core/handlers/base.py\" in _get_response\n  187.                 response = self.process_exception_by_middleware(e, request)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/core/handlers/base.py\" in _get_response\n  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/views/decorators/csrf.py\" in wrapped_view\n  58.         return view_func(*args, **kwargs)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/views/generic/base.py\" in view\n  68.             return self.dispatch(request, *args, **kwargs)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/rest_framework/views.py\" in dispatch\n  495.             response = self.handle_exception(exc)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/rest_framework/views.py\" in handle_exception\n  455.             self.raise_uncaught_exception(exc)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/rest_framework/views.py\" in dispatch\n  492.             response = handler(request, *args, **kwargs)\n\nFile \"/Users/d/Projects/le/develop/kolibri/core/device/api.py\" in get\n  93.         instance_model = InstanceIDModel.get_or_create_current_instance()[0]\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/contextlib.py\" in inner\n  74.                 return func(*args, **kwds)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/morango/models/core.py\" in get_or_create_current_instance\n  141.             current=False\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/query.py\" in update\n  650.             rows = query.get_compiler(self.db).execute_sql(CURSOR)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/sql/compiler.py\" in execute_sql\n  1204.         cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/sql/compiler.py\" in execute_sql\n  899.             raise original_exception\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/sql/compiler.py\" in execute_sql\n  889.             cursor.execute(sql, params)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py\" in execute\n  79.             return super(CursorDebugWrapper, self).execute(sql, params)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py\" in execute\n  64.                 return self.cursor.execute(sql, params)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/utils.py\" in __exit__\n  94.                 six.reraise(dj_exc_type, dj_exc_value, traceback)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/utils/six.py\" in reraise\n  685.             raise value.with_traceback(tb)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py\" in execute\n  64.                 return self.cursor.execute(sql, params)\n\nFile \"/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py\" in execute\n  328.         return Database.Cursor.execute(self, query, params)\n\nException Type: OperationalError at /api/device/deviceinfo/\nException Value: database is locked\nRequest information:\nUSER: \"d\"@\"Home Facility d\"\n\nGET:\n1592863732768 = '1592863732768'\n\nPOST: No POST data\n\nFILES: No FILES data\n\nCOOKIES:\nvisitor_id = '801031c1-9b9c-4a7c-993a-c6c46f470f4c'\ncsrftoken = 'VXRNoeATLHpnG7kgNulqNarj0ycqo6Gg'\nkolibri_csrftoken = 'c1wmeBcx6fnR3DdpsPgUtOEhM6nBFTbE8RSHVsOR6lfbYvBwkX7W91HFxrW34SOo'\nkolibri = 'ijy0z7x1nz1mfdhup8dmvsd3ac7dzju5'\n\nMETA:\nCFLAGS = '-I/usr/local/opt/openssl@1.1/include'\nCMAKE_PREFIX_PATH = '/usr/local/opt/qt:/usr/local/opt/qt'\nCONTENT_LENGTH = ''\nCONTENT_TYPE = 'text/plain'\nCROWDIN_API_KEY = '4734ac31a65acc36072dce32e9226ca0'\nCSRF_COOKIE = 'c1wmeBcx6fnR3DdpsPgUtOEhM6nBFTbE8RSHVsOR6lfbYvBwkX7W91HFxrW34SOo'\nDJANGO_SETTINGS_MODULE = 'kolibri.deployment.default.settings.dev'\nEDITOR = 'nano'\nGATEWAY_INTERFACE = 'CGI/1.1'\nHOME = '/Users/d'\nHTTP_ACCEPT = 'application/json, text/plain, */*'\nHTTP_ACCEPT_ENCODING = 'gzip, deflate, br'\nHTTP_ACCEPT_LANGUAGE = 'en-US,en;q=0.9,es;q=0.8'\nHTTP_CACHE_CONTROL = 'no-cache'\nHTTP_CONNECTION = 'keep-alive'\nHTTP_COOKIE = 'visitor_id=801031c1-9b9c-4a7c-993a-c6c46f470f4c; csrftoken=VXRNoeATLHpnG7kgNulqNarj0ycqo6Gg; kolibri_csrftoken=c1wmeBcx6fnR3DdpsPgUtOEhM6nBFTbE8RSHVsOR6lfbYvBwkX7W91HFxrW34SOo; kolibri=ijy0z7x1nz1mfdhup8dmvsd3ac7dzju5'\nHTTP_HOST = 'localhost:8000'\nHTTP_PRAGMA = 'no-cache'\nHTTP_REFERER = 'http://localhost:8000/en/device/'\nHTTP_SEC_FETCH_DEST = 'empty'\nHTTP_SEC_FETCH_MODE = 'cors'\nHTTP_SEC_FETCH_SITE = 'same-origin'\nHTTP_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36'\nHTTP_X_CSRFTOKEN = 'c1wmeBcx6fnR3DdpsPgUtOEhM6nBFTbE8RSHVsOR6lfbYvBwkX7W91HFxrW34SOo'\nINIT_CWD = '/Users/d/Projects/le/develop'\nKOLIBRI_HOME = '~/kolibri/014x'\nKOLIBRI_RUN_MODE = 'd10'\nLANG = 'en_US.UTF-8'\nLDFLAGS = '-I/usr/local/opt/openssl@1.1/lib'\nLOGNAME = 'd'\nNODE = '/Users/d/.nvm/versions/node/v10.15.3/bin/node'\nNPM_CONFIG_PYTHON = '/usr/bin/python'\nNVM_BIN = '/Users/d/.nvm/versions/node/v10.15.3/bin'\nNVM_CD_FLAGS = ''\nNVM_DIR = '/Users/d/.nvm'\nOPENSSL_ROOT_DIR = '/usr/local/opt/openssl@1.1'\nPATH = '/Users/d/.pyenv/versions/3.7.6/bin:/usr/local/Cellar/pyenv/1.2.16/libexec:/Users/d/.nvm/versions/node/v10.15.3/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/d/Projects/le/develop/node_modules/.bin:/var/folders/9r/4w5cgtz95c5csjr86rv9qm_h0000gp/T/yarn--1592843704038-0.08180204294255322:/Users/d/Projects/le/develop/node_modules/.bin:/Users/d/.config/yarn/link/node_modules/.bin:/Users/d/Projects/le/develop/node_modules/.bin:/Users/d/.nvm/versions/node/v10.15.3/libexec/lib/node_modules/npm/bin/node-gyp-bin:/Users/d/.nvm/versions/node/v10.15.3/lib/node_modules/npm/bin/node-gyp-bin:/Users/d/.nvm/versions/node/v10.15.3/bin/node_modules/npm/bin/node-gyp-bin:/Users/d/Projects/le/kolibri/.venv/bin:/Users/d/.pyenv/shims:/Users/d/.pyenv/bin:/Users/d/.nvm/versions/node/v10.15.3/bin:/Users/d/bin:/Users/d/.yarn/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/Cellar/pipenv/2018.11.26_4/libexec/tools:/Users/d/.pyenv/shims:/Users/d/.pyenv/bin:/Users/d/google-cloud-sdk/bin:/Users/d/.nvm/versions/node/v10.15.3/bin:/Users/d/bin:/Users/d/.yarn/bin:/usr/local/opt/gettext/bin:/usr/local/opt/qt/bin:/usr/local/opt/gettext/bin:/usr/local/opt/qt/bin'\nPATH_INFO = '/api/device/deviceinfo/'\nPIPENV_ACTIVE = '1'\nPIPENV_SHELL = '/usr/local/bin/fish'\nPIPENV_VENV_IN_PROJECT = '1'\nPIP_DISABLE_PIP_VERSION_CHECK = '1'\nPIP_PYTHON_PATH = '/usr/local/Cellar/pipenv/2018.11.26_4/libexec/bin/python3.8'\nPREFIX = '/usr/local'\nPWD = '/Users/d/Projects/le/develop'\nPYENV_DIR = '/Users/d/Projects/le/develop'\nPYENV_HOOK_PATH = '/Users/d/.pyenv/pyenv.d:/usr/local/Cellar/pyenv/1.2.16/pyenv.d:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks'\nPYENV_ROOT = '/Users/d/.pyenv'\nPYENV_SHELL = 'fish'\nPYENV_VERSION = '3.7.6'\nPYTHONDONTWRITEBYTECODE = '1'\nQUERY_STRING = '1592863732768=1592863732768'\nREMOTE_ADDR = '127.0.0.1'\nREMOTE_HOST = ''\nREQUEST_METHOD = 'GET'\nRUN_MAIN = 'true'\nSCRIPT_NAME = ''\nSERVER_NAME = '1.0.0.127.in-addr.arpa'\nSERVER_PORT = '8000'\nSERVER_PROTOCOL = 'HTTP/1.1'\nSERVER_SOFTWARE = 'WSGIServer/0.2'\nSHELL = '/bin/bash'\nSHLVL = '4'\nSSH_AUTH_SOCK = '/private/tmp/com.apple.launchd.APQR8GJwlp/Listeners'\nTERM = 'xterm-256color'\nTERM_PROGRAM = 'Apple_Terminal'\nTERM_PROGRAM_VERSION = '433'\nTERM_SESSION_ID = 'CDB8FD7C-1BAF-4707-8872-349BCCF38896'\nTMPDIR = '/var/folders/9r/4w5cgtz95c5csjr86rv9qm_h0000gp/T/'\nTZ = 'America/Los_Angeles'\nUSER = 'd'\nVIRTUAL_ENV = '/Users/d/Projects/le/kolibri/.venv'\nXPC_FLAGS = '0x0'\nXPC_SERVICE_NAME = '0'\nYARN_WRAP_OUTPUT = 'false'\n_OLD_FISH_PROMPT_OVERRIDE = '/Users/d/Projects/le/kolibri/.venv'\n_OLD_VIRTUAL_PATH = '/Users/d/.pyenv/shims:/Users/d/.pyenv/bin:/Users/d/.nvm/versions/node/v10.15.3/bin:/Users/d/bin:/Users/d/.yarn/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/Cellar/pipenv/2018.11.26_4/libexec/tools:/Users/d/.pyenv/shims:/Users/d/.pyenv/bin:/Users/d/google-cloud-sdk/bin:/Users/d/.nvm/versions/node/v10.15.3/bin:/Users/d/bin:/Users/d/.yarn/bin:/usr/local/opt/gettext/bin:/usr/local/opt/qt/bin:/usr/local/opt/gettext/bin:/usr/local/opt/qt/bin'\n__CF_USER_TEXT_ENCODING = '0x1F6:0x0:0x0'\nnpm_config_access = ''\nnpm_config_allow_same_version = ''\nnpm_config_also = ''\nnpm_config_always_auth = ''\nnpm_config_argv = '{\"remain\":[],\"cooked\":[\"run\",\"django-devserver-no-update\"],\"original\":[\"run\",\"django-devserver-no-update\"]}'\nnpm_config_audit = 'true'\nnpm_config_audit_level = 'low'\nnpm_config_auth_type = 'legacy'\nnpm_config_bin_links = 'true'\nnpm_config_browser = ''\nnpm_config_ca = ''\nnpm_config_cache = '/Users/d/.npm'\nnpm_config_cache_lock_retries = '10'\nnpm_config_cache_lock_stale = '60000'\nnpm_config_cache_lock_wait = '10000'\nnpm_config_cache_max = 'Infinity'\nnpm_config_cache_min = '10'\nnpm_config_cafile = ''\nnpm_config_cert = ''\nnpm_config_cidr = ''\nnpm_config_color = 'true'\nnpm_config_commit_hooks = 'true'\nnpm_config_depth = 'Infinity'\nnpm_config_description = 'true'\nnpm_config_dev = ''\nnpm_config_dry_run = ''\nnpm_config_editor = 'nano'\nnpm_config_engine_strict = ''\nnpm_config_fetch_retries = '2'\nnpm_config_fetch_retry_factor = '10'\nnpm_config_fetch_retry_maxtimeout = '60000'\nnpm_config_fetch_retry_mintimeout = '10000'\nnpm_config_force = ''\nnpm_config_git = 'git'\nnpm_config_git_tag_version = 'true'\nnpm_config_global = ''\nnpm_config_global_style = ''\nnpm_config_globalconfig = '/Users/d/.yarn/etc/npmrc'\nnpm_config_globalignorefile = '/Users/d/.yarn/etc/npmignore'\nnpm_config_group = '20'\nnpm_config_ham_it_up = ''\nnpm_config_heading = 'npm'\nnpm_config_https_proxy = ''\nnpm_config_if_present = ''\nnpm_config_ignore_prepublish = ''\nnpm_config_ignore_scripts = ''\nnpm_config_init_author_email = ''\nnpm_config_init_author_name = ''\nnpm_config_init_author_url = ''\nnpm_config_init_license = 'MIT'\nnpm_config_init_module = '/Users/d/.npm-init.js'\nnpm_config_init_version = '1.0.0'\nnpm_config_json = ''\nnpm_config_key = ''\nnpm_config_legacy_bundling = ''\nnpm_config_link = ''\nnpm_config_local_address = ''\nnpm_config_loglevel = 'notice'\nnpm_config_logs_max = '10'\nnpm_config_long = ''\nnpm_config_maxsockets = '50'\nnpm_config_message = '%s'\nnpm_config_metrics_registry = 'https://registry.yarnpkg.com/'\nnpm_config_node_gyp = '/Users/d/.nvm/versions/node/v10.15.3/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js'\nnpm_config_node_options = ''\nnpm_config_node_version = '10.15.3'\nnpm_config_noproxy = ''\nnpm_config_offline = ''\nnpm_config_onload_script = ''\nnpm_config_only = ''\nnpm_config_optional = 'true'\nnpm_config_otp = ''\nnpm_config_package_lock = 'true'\nnpm_config_package_lock_only = ''\nnpm_config_parseable = ''\nnpm_config_prefer_offline = ''\nnpm_config_prefer_online = ''\nnpm_config_prefix = '/Users/d/.yarn'\nnpm_config_preid = ''\nnpm_config_production = ''\nnpm_config_progress = 'true'\nnpm_config_proxy = ''\nnpm_config_python = '/usr/bin/python'\nnpm_config_read_only = ''\nnpm_config_rebuild_bundle = 'true'\nnpm_config_registry = 'https://registry.yarnpkg.com/'\nnpm_config_rollback = 'true'\nnpm_config_save = 'true'\nnpm_config_save_bundle = ''\nnpm_config_save_dev = ''\nnpm_config_save_exact = ''\nnpm_config_save_optional = ''\nnpm_config_save_prefix = '^'\nnpm_config_save_prod = ''\nnpm_config_scope = ''\nnpm_config_script_shell = ''\nnpm_config_scripts_prepend_node_path = 'warn-only'\nnpm_config_searchexclude = ''\nnpm_config_searchlimit = '20'\nnpm_config_searchopts = ''\nnpm_config_searchstaleness = '900'\nnpm_config_send_metrics = ''\nnpm_config_shell = '/bin/bash'\nnpm_config_shrinkwrap = 'true'\nnpm_config_sign_git_commit = ''\nnpm_config_sign_git_tag = ''\nnpm_config_sso_poll_frequency = '500'\nnpm_config_sso_type = 'oauth'\nnpm_config_strict_ssl = 'true'\nnpm_config_tag = 'latest'\nnpm_config_tag_version_prefix = 'v'\nnpm_config_timing = ''\nnpm_config_tmp = '/var/folders/9r/4w5cgtz95c5csjr86rv9qm_h0000gp/T'\nnpm_config_umask = '0022'\nnpm_config_unicode = 'true'\nnpm_config_unsafe_perm = 'true'\nnpm_config_update_notifier = 'true'\nnpm_config_usage = ''\nnpm_config_user = '502'\nnpm_config_user_agent = 'yarn/1.22.4 npm/? node/v10.15.3 darwin x64'\nnpm_config_userconfig = '/Users/d/.npmrc'\nnpm_config_version = ''\nnpm_config_version_commit_hooks = 'true'\nnpm_config_version_git_message = 'v%s'\nnpm_config_version_git_tag = 'true'\nnpm_config_version_tag_prefix = 'v'\nnpm_config_versions = ''\nnpm_config_viewer = 'man'\nnpm_execpath = '/Users/d/.nvm/versions/node/v10.15.3/lib/node_modules/npm/bin/npm-cli.js'\nnpm_lifecycle_event = 'django-devserver-no-update'\nnpm_lifecycle_script = 'kolibri manage --debug --skip-update runserver --settings=kolibri.deployment.default.settings.dev \"0.0.0.0:8000\" '\nnpm_node_execpath = '/Users/d/.nvm/versions/node/v10.15.3/bin/node'\nnpm_package_author_name = 'Learning Equality'\nnpm_package_bugs_url = 'https://github.com/learningequality/kolibri/issues'\nnpm_package_dependencies_fsevents = '*'\nnpm_package_description = 'Development utilities for Kolibri'\nnpm_package_devDependencies__types_jest = '^24.0.12'\nnpm_package_devDependencies_black_fmt = 'git+https://github.com/learningequality/black-fmt.git#v0.1.3'\nnpm_package_devDependencies_kolibri_tools = '0.13.0-dev.10'\nnpm_package_devDependencies_xhr_mock = '^2.5.1'\nnpm_package_devDependencies_yarn_run_all = '^3.1.1'\nnpm_package_engineStrict = 'true'\nnpm_package_engines_node = '10.x'\nnpm_package_engines_yarn = '>= 1.12.3'\nnpm_package_gitHead = 'fe997ef0bfa150c01f067602b5644bda484bbf27'\nnpm_package_homepage = 'https://github.com/learningequality/kolibri#readme'\nnpm_package_license = 'MIT'\nnpm_package_name = 'kolibri-root'\nnpm_package_optionalDependencies_fsevents = '*'\nnpm_package_private = 'true'\nnpm_package_readmeFilename = 'README.md'\nnpm_package_repository_type = 'git'\nnpm_package_repository_url = 'git+https://github.com/learningequality/kolibri.git'\nnpm_package_scripts_build = 'kolibri-tools build prod --file ./build_tools/build_plugins.txt && yarn run hashi-build'\nnpm_package_scripts_build_kolibri_tools = 'yarn workspace kolibri-tools run build-kolibri-tools'\nnpm_package_scripts_bundle_stats = 'kolibri-tools build stats --file ./build_tools/build_plugins.txt'\nnpm_package_scripts_clean = 'kolibri-tools build clean --file ./build_tools/build_plugins.txt'\nnpm_package_scripts_combineprofiles = 'node ./packages/kolibri-tools/lib/combineStringProfiles.js ./kolibri/locale/en/LC_MESSAGES/profiles/'\nnpm_package_scripts_coverage = 'yarn run test-jest-cov'\nnpm_package_scripts_devserver = 'npm-run-all --parallel django-devserver-no-update lint-frontend:watch:format hashi-dev watch services'\nnpm_package_scripts_devserver_hot = 'npm-run-all --parallel django-devserver-no-update lint-frontend:watch:format hashi-dev watch-hot services'\nnpm_package_scripts_devserver_hot_warn = 'npm-run-all --parallel django-devserver-no-update lint-frontend:watch hashi-dev watch-hot services'\nnpm_package_scripts_devserver_services = 'npm-run-all --parallel django-devserver-no-update services'\nnpm_package_scripts_devserver_warn = 'npm-run-all --parallel django-devserver-no-update lint-frontend:watch hashi-dev watch services'\nnpm_package_scripts_django_devserver = 'kolibri manage --debug runserver --settings=kolibri.deployment.default.settings.dev \"0.0.0.0:8000\" '\nnpm_package_scripts_django_devserver_no_update = 'kolibri manage --debug --skip-update runserver --settings=kolibri.deployment.default.settings.dev \"0.0.0.0:8000\" '\nnpm_package_scripts_fmt_backend = 'yarn run black-fmt'\nnpm_package_scripts_fmt_backend_check = 'yarn run black-fmt --check'\nnpm_package_scripts_fmt_backend_watch = 'yarn run black-fmt --watch'\nnpm_package_scripts_hashi_build = 'yarn workspace hashi run build'\nnpm_package_scripts_hashi_dev = 'yarn workspace hashi run dev'\nnpm_package_scripts_lint_frontend = \"kolibri-tools lint '{kolibri*/**/assets,packages}/**/*.{js,vue,scss,less,css}' --ignore '**/node_modules/**','**/static/**','**/packages/kolibri-core-for-export/**'\"\nnpm_package_scripts_lint_frontend_format = 'yarn run lint-frontend --write'\nnpm_package_scripts_lint_frontend_watch = 'yarn run lint-frontend --monitor'\nnpm_package_scripts_lint_frontend_watch_format = 'yarn run lint-frontend --monitor --write'\nnpm_package_scripts_makemessages = 'kolibri-tools build i18n --file ./build_tools/build_plugins.txt'\nnpm_package_scripts_preinstall = 'node ./packages/kolibri-tools/lib/npm_deprecation_warning.js'\nnpm_package_scripts_publish_packages = 'node ./packages/publish.js'\nnpm_package_scripts_services = 'kolibri services --foreground --port=8000'\nnpm_package_scripts_test = 'yarn run test-jest --watch'\nnpm_package_scripts_test_jest = 'kolibri-tools test --config ./jest.conf.js'\nnpm_package_scripts_test_jest_cov = 'yarn run test-jest --coverage'\nnpm_package_scripts_transfercontext = 'node ./packages/kolibri-tools/lib/i18nSyncContext.js run && yarn lint-frontend:format'\nnpm_package_scripts_watch = 'kolibri-tools build dev --file ./build_tools/build_plugins.txt'\nnpm_package_scripts_watch_hot = 'yarn run watch --hot'\nnpm_package_version = '0.12.0-dev.1'\nnpm_package_workspaces_0 = 'packages/*'\nnpm_package_workspaces_1 = 'kolibri/core'\nnpm_package_workspaces_2 = 'kolibri/plugins/*'\nwsgi.errors = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>\nwsgi.file_wrapper = ''\nwsgi.input = <_io.BufferedReader name=11>\nwsgi.multiprocess = False\nwsgi.multithread = True\nwsgi.run_once = False\nwsgi.url_scheme = 'http'\nwsgi.version = '(1, 0)'\n\nSettings:\nUsing settings module kolibri.deployment.default.settings.dev\nABSOLUTE_URL_OVERRIDES = {}\nADMINS = []\nALLOWED_HOSTS = ['*']\nAPPEND_SLASH = True\nAUTHENTICATION_BACKENDS = ['kolibri.core.auth.backends.FacilityUserBackend']\nAUTH_ANONYMOUS_USER_MODEL = 'kolibriauth.KolibriAnonymousUser'\nAUTH_PASSWORD_VALIDATORS = '********************'\nAUTH_USER_MODEL = 'kolibriauth.FacilityUser'\nBASE_DIR = '/Users/d/Projects/le/develop'\nCACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}, 'built_files': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}, 'process_cache': {'BACKEND': 'diskcache.DjangoCache', 'LOCATION': '/Users/d/kolibri/014x/process_cache', 'OPTIONS': {'MAX_ENTRIES': 1000, 'disk_pickle_protocol': 2}}}\nCACHE_MIDDLEWARE_ALIAS = 'default'\nCACHE_MIDDLEWARE_KEY_PREFIX = '********************'\nCACHE_MIDDLEWARE_SECONDS = 0\nCSRF_COOKIE_AGE = 31449600\nCSRF_COOKIE_DOMAIN = None\nCSRF_COOKIE_HTTPONLY = False\nCSRF_COOKIE_NAME = 'kolibri_csrftoken'\nCSRF_COOKIE_PATH = '/'\nCSRF_COOKIE_SECURE = False\nCSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure'\nCSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'\nCSRF_TRUSTED_ORIGINS = []\nCSRF_USE_SESSIONS = False\nDATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': '/Users/d/kolibri/014x/db.sqlite3', 'OPTIONS': {'timeout': 100}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'TIME_ZONE': None, 'USER': '', 'PASSWORD': '********************', 'HOST': '', 'PORT': '', 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}, 'notifications_db': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': '/Users/d/kolibri/014x/notifications.sqlite3', 'OPTIONS': {'timeout': 100}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'TIME_ZONE': None, 'USER': '', 'PASSWORD': '********************', 'HOST': '', 'PORT': '', 'TEST': {'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}}}\nDATABASE_ROUTERS = \"('kolibri.core.notifications.models.NotificationsRouter',)\"\nDATA_UPLOAD_MAX_MEMORY_SIZE = 2621440\nDATA_UPLOAD_MAX_NUMBER_FIELDS = 1000\nDATETIME_FORMAT = 'N j, Y, P'\nDATETIME_INPUT_FORMATS = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S.%f', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M:%S.%f', '%m/%d/%y %H:%M', '%m/%d/%y']\nDATE_FORMAT = 'N j, Y'\nDATE_INPUT_FORMATS = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y']\nDEBUG = True\nDEBUG_PROPAGATE_EXCEPTIONS = False\nDECIMAL_SEPARATOR = '.'\nDEFAULT_CHARSET = 'utf-8'\nDEFAULT_CONTENT_TYPE = 'text/html'\nDEFAULT_EXCEPTION_REPORTER_FILTER = 'django.views.debug.SafeExceptionReporterFilter'\nDEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'\nDEFAULT_FROM_EMAIL = 'webmaster@localhost'\nDEFAULT_INDEX_TABLESPACE = ''\nDEFAULT_TABLESPACE = ''\nDEVELOPER_MODE = True\nDISALLOWED_USER_AGENTS = []\nEMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'\nEMAIL_HOST = 'localhost'\nEMAIL_HOST_PASSWORD = '********************'\nEMAIL_HOST_USER = ''\nEMAIL_PORT = 25\nEMAIL_SSL_CERTFILE = None\nEMAIL_SSL_KEYFILE = '********************'\nEMAIL_SUBJECT_PREFIX = '[Django] '\nEMAIL_TIMEOUT = None\nEMAIL_USE_LOCALTIME = False\nEMAIL_USE_SSL = False\nEMAIL_USE_TLS = False\nENABLE_DATA_BOOTSTRAPPING = True\nEXTRA_LANG_INFO = {'ff-cm': {'bidi': False, 'code': 'ff-cm', 'name': 'Fulfulde (Cameroon)', 'name_local': 'Fulfulde Mbororoore', 'name_translated': 'Fulfulde (Cameroon)'}, 'es-419': {'bidi': False, 'code': 'es-419', 'name': 'Spanish (Latin America)', 'name_local': 'Español', 'name_translated': 'Spanish (Latin America)'}, 'es-es': {'bidi': False, 'code': 'es-es', 'name': 'Spanish (Spain)', 'name_local': 'Español (España)', 'name_translated': 'Spanish (Spain)'}, 'fr-ht': {'bidi': False, 'code': 'fr-ht', 'name': 'Haitian Creole', 'name_local': 'Kreyòl ayisyen'}, 'gu-in': {'bidi': False, 'code': 'gu-in', 'name': 'Gujarati', 'name_local': 'ગુજરાતી', 'name_translated': 'Gujarati'}, 'nyn': {'bidi': False, 'code': 'nyn', 'name': 'Chichewa, Chewa, Nyanja', 'name_local': 'Chinyanja', 'name_translated': 'Chichewa, Chewa, Nyanja'}, 'zh': {'bidi': False, 'code': 'zh-hans', 'name': 'Simplified Chinese', 'name_local': '简体中文'}, 'yo': {'bidi': False, 'code': 'yo', 'name': 'Yoruba', 'name_local': 'Yorùbá', 'name_translated': 'Yoruba'}, 'zu': {'bidi': False, 'code': 'zu', 'name': 'Zulu', 'name_local': 'isiZulu'}}\nFILE_CHARSET = 'utf-8'\nFILE_UPLOAD_DIRECTORY_PERMISSIONS = None\nFILE_UPLOAD_HANDLERS = ['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler']\nFILE_UPLOAD_MAX_MEMORY_SIZE = 2621440\nFILE_UPLOAD_PERMISSIONS = None\nFILE_UPLOAD_TEMP_DIR = None\nFIRST_DAY_OF_WEEK = 0\nFIXTURE_DIRS = []\nFORCE_SCRIPT_NAME = None\nFORMAT_MODULE_PATH = None\nFORM_RENDERER = 'django.forms.renderers.DjangoTemplates'\nIGNORABLE_404_URLS = []\nINSTALLED_APPS = ['kolibri.core', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django_filters', 'kolibri.core.auth.apps.KolibriAuthConfig', 'kolibri.core.content', 'kolibri.core.logger', 'kolibri.core.notifications.apps.KolibriNotificationsConfig', 'kolibri.core.tasks.apps.KolibriTasksConfig', 'kolibri.core.deviceadmin', 'kolibri.core.webpack', 'kolibri.core.exams', 'kolibri.core.device', 'kolibri.core.discovery', 'kolibri.core.lessons', 'kolibri.core.analytics', 'rest_framework', 'django_js_reverse', 'jsonfield', 'morango', <AppConfig: kolibri.plugins.html5_viewer>, <AppConfig: kolibri.plugins.setup_wizard>, <AppConfig: kolibri_exercise_perseus_plugin>, <AppConfig: kolibri.plugins.learn>, <AppConfig: kolibri.plugins.slideshow_viewer>, <AppConfig: kolibri.plugins.facility>, <AppConfig: kolibri.plugins.user>, <AppConfig: kolibri.plugins.device>, <AppConfig: kolibri.plugins.epub_viewer>, <AppConfig: kolibri.plugins.pdf_viewer>, <AppConfig: kolibri.plugins.media_player>, <AppConfig: kolibri.plugins.coach>, <AppConfig: kolibri.plugins.default_theme>, 'drf_yasg']\nINTERNAL_IPS = ['127.0.0.1']\nJS_REVERSE_EXCLUDE_NAMESPACES = ['admin']\nKOLIBRI_MODULE_PATH = '/Users/d/Projects/le/develop/kolibri'\nLANGUAGES = [('ar', 'العَرَبِيَّة\\u200e\\u200e'), ('bg-bg', 'Български'), ('bn-bd', 'বাংলা'), ('en', 'English'), ('es-419', 'Español'), ('es-es', 'Español (España)'), ('fa', 'فارسی'), ('ff-cm', 'Fulfulde Mbororoore'), ('fr-fr', 'Français'), ('gu-in', 'ગુજરાતી'), ('hi-in', 'हिंदी (भारत)'), ('it', 'Italiano'), ('ko', '한국어'), ('mr', 'मराठी'), ('my', 'ဗမာစာ'), ('nyn', 'Chinyanja'), ('pt-br', 'Português'), ('sw-tz', 'Kiswahili'), ('te', 'తెలుగు'), ('ur-pk', 'اُردو (پاکستان)\\u200f'), ('vi', 'Tiếng Việt'), ('yo', 'Yorùbá'), ('zh-hans', '简体中文')]\nLANGUAGES_BIDI = ['he', 'ar', 'fa', 'ur']\nLANGUAGE_CODE = 'en'\nLANGUAGE_COOKIE_AGE = None\nLANGUAGE_COOKIE_DOMAIN = None\nLANGUAGE_COOKIE_NAME = 'django_language'\nLANGUAGE_COOKIE_PATH = '/'\nLOCALE_PATHS = \"('/Users/d/Projects/le/develop/kolibri/locale', '/Users/d/Projects/le/perseus-plugin/kolibri_exercise_perseus_plugin/locale')\"\nLOGGING = {'version': 1, 'disable_existing_loggers': False, 'filters': {'require_debug_true': {'()': <class 'kolibri.utils.logger.RequireDebugTrue'>}, 'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}}, 'formatters': {'verbose': {'format': '%(levelname)s %(asctime)s %(name)s %(process)d %(thread)d %(message)s'}, 'simple': {'format': '%(levelname)s %(message)s'}, 'simple_date': {'format': '%(levelname)s %(asctime)s %(name)s %(message)s'}, 'simple_date_file': {'()': 'kolibri.utils.logger.KolibriLogFileFormatter', 'format': '%(levelname)s %(asctime)s %(name)s %(message)s'}, 'color': {'()': 'colorlog.ColoredFormatter', 'format': '%(log_color)s%(levelname)-8s %(message)s', 'log_colors': {'DEBUG': 'bold_black', 'INFO': 'white', 'WARNING': 'yellow', 'ERROR': 'red', 'CRITICAL': 'bold_red'}}}, 'handlers': {'console': {'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'color'}, 'file': {'level': 'INFO', 'filters': [], 'class': 'kolibri.utils.logger.KolibriTimedRotatingFileHandler', 'filename': '/Users/d/kolibri/014x/logs/kolibri.txt', 'formatter': 'simple_date_file', 'when': 'midnight', 'backupCount': 30}, 'file_debug': {'level': 'DEBUG', 'filters': ['require_debug_true'], 'class': 'logging.FileHandler', 'filename': '/Users/d/kolibri/014x/logs/debug.txt', 'formatter': 'simple_date'}, 'mail_admins': {'level': 'ERROR', 'class': 'django.utils.log.AdminEmailHandler', 'filters': ['require_debug_false']}}, 'loggers': {'kolibri': {'handlers': ['file', 'console', 'file_debug', 'mail_admins'], 'level': 'INFO', 'propagate': False}, 'kolibri.core.tasks.worker': {'handlers': ['file', 'console', 'file_debug'], 'level': 'INFO', 'propagate': False}, 'morango': {'handlers': ['file', 'console', 'file_debug'], 'level': 'INFO', 'propagate': False}, 'django': {'handlers': ['file', 'console', 'file_debug', 'mail_admins'], 'level': 'INFO', 'propagate': False}, 'django.db.backends': {'handlers': ['file', 'console', 'file_debug'], 'level': 'INFO', 'propagate': False}, 'django.request': {'handlers': ['file', 'console', 'file_debug', 'mail_admins'], 'level': 'INFO', 'propagate': False}, 'cherrypy.access': {'handlers': ['file', 'console', 'file_debug'], 'level': 'INFO', 'propagate': False}, 'cherrypy.error': {'handlers': ['file', 'console', 'file_debug'], 'level': 'INFO', 'propagate': False}, 'cherrypy': {'handlers': ['file', 'console', 'file_debug'], 'level': 'INFO', 'propagate': False}}}\nLOGGING_CONFIG = 'logging.config.dictConfig'\nLOGIN_REDIRECT_URL = '/accounts/profile/'\nLOGIN_URL = '/accounts/login/'\nLOGOUT_REDIRECT_URL = None\nMANAGERS = []\nMEDIA_ROOT = '/Users/d/kolibri/014x/media'\nMEDIA_URL = '/media/'\nMESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'\nMIDDLEWARE = ['kolibri.core.analytics.middleware.cherrypy_access_log_middleware', 'kolibri.core.device.middleware.ProvisioningErrorHandler', 'django.middleware.cache.UpdateCacheMiddleware', 'kolibri.core.analytics.middleware.MetricsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'kolibri.core.device.middleware.KolibriLocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'kolibri.core.auth.middleware.CustomAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware', 'kolibri.core.webpack.middleware.WebpackErrorHandler']\nMIDDLEWARE_CLASSES = ['django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware']\nMIGRATION_MODULES = {}\nMONTH_DAY_FORMAT = 'F j'\nNUMBER_GROUPING = 0\nPASSWORD_HASHERS = '********************'\nPASSWORD_RESET_TIMEOUT_DAYS = '********************'\nPREPEND_WWW = False\nREST_FRAMEWORK = {'UNAUTHENTICATED_USER': 'kolibri.core.auth.models.KolibriAnonymousUser', 'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication'], 'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer'), 'EXCEPTION_HANDLER': 'kolibri.core.utils.exception_handler.custom_exception_handler'}\nROOT_URLCONF = 'kolibri.deployment.default.dev_urls'\nSECRET_KEY = '********************'\nSECURE_BROWSER_XSS_FILTER = False\nSECURE_CONTENT_TYPE_NOSNIFF = False\nSECURE_HSTS_INCLUDE_SUBDOMAINS = False\nSECURE_HSTS_PRELOAD = False\nSECURE_HSTS_SECONDS = 0\nSECURE_PROXY_SSL_HEADER = None\nSECURE_REDIRECT_EXEMPT = []\nSECURE_SSL_HOST = None\nSECURE_SSL_REDIRECT = False\nSERVER_EMAIL = 'root@localhost'\nSESSION_CACHE_ALIAS = 'default'\nSESSION_COOKIE_AGE = 1200\nSESSION_COOKIE_DOMAIN = None\nSESSION_COOKIE_HTTPONLY = True\nSESSION_COOKIE_NAME = 'kolibri'\nSESSION_COOKIE_PATH = '/'\nSESSION_COOKIE_SECURE = False\nSESSION_ENGINE = 'django.contrib.sessions.backends.file'\nSESSION_EXPIRE_AT_BROWSER_CLOSE = True\nSESSION_FILE_PATH = '/Users/d/kolibri/014x/sessions'\nSESSION_SAVE_EVERY_REQUEST = False\nSESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'\nSETTINGS_MODULE = 'kolibri.deployment.default.settings.dev'\nSHORT_DATETIME_FORMAT = 'm/d/Y P'\nSHORT_DATE_FORMAT = 'm/d/Y'\nSIGNING_BACKEND = 'django.core.signing.TimestampSigner'\nSILENCED_SYSTEM_CHECKS = ['auth.W004']\nSTATICFILES_DIRS = []\nSTATICFILES_FINDERS = ['django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder']\nSTATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'\nSTATIC_ROOT = '/Users/d/kolibri/014x/static'\nSTATIC_URL = '/static/'\nTEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'kolibri.core.context_processors.custom_context_processor.developer_mode']}}]\nTEST_NON_SERIALIZED_APPS = []\nTEST_RUNNER = 'django.test.runner.DiscoverRunner'\nTHOUSAND_SEPARATOR = ','\nTIME_FORMAT = 'P'\nTIME_INPUT_FORMATS = ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']\nTIME_ZONE = 'America/Los_Angeles'\nUSE_ETAGS = False\nUSE_I18N = True\nUSE_L10N = True\nUSE_THOUSAND_SEPARATOR = False\nUSE_TZ = True\nUSE_X_FORWARDED_HOST = False\nUSE_X_FORWARDED_PORT = False\nWSGI_APPLICATION = 'kolibri.deployment.default.wsgi.application'\nX_FRAME_OPTIONS = 'SAMEORIGIN'\nYEAR_MONTH_FORMAT = 'F Y'\n\n\nYou're seeing this error because you have DEBUG = True in your\nDjango settings file. Change that to False, and Django will\ndisplay a standard page generated by the handler for this status code.\n\n",
  "status": 500,
  "statusText": "Internal Server Error",
  "headers": {
    "content-length": "35276",
    "content-type": "text/plain",
    "date": "Mon, 22 Jun 2020 22:08:53 GMT",
    "server": "WSGIServer/0.2 CPython/3.7.6",
    "vary": "Cookie",
    "x-frame-options": "SAMEORIGIN"
  },
  "config": {
    "url": "/api/device/deviceinfo/",
    "params": {
      "1592863732768": 1592863732768
    },
    "headers": {
      "Accept": "application/json, text/plain, */*",
      "X-CSRFToken": "c1wmeBcx6fnR3DdpsPgUtOEhM6nBFTbE8RSHVsOR6lfbYvBwkX7W91HFxrW34SOo"
    },
    "transformRequest": [
      null
    ],
    "transformResponse": [
      null
    ],
    "timeout": 0,
    "xsrfCookieName": "kolibri_csrftoken",
    "xsrfHeaderName": "X-CSRFToken",
    "maxContentLength": -1,
    "method": "get"
  },
  "request": {}
}

Expected behavior

Able to view device info while import/export is occurring

User-facing consequences

broken functionality and unexpected error, or possibly finding a workaround for more gracefully handling this situation if locking is innevitable

Errors and logs

ERROR    Internal Server Error: /api/device/deviceinfo/
Traceback (most recent call last):
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: database is locked

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/rest_framework/views.py", line 495, in dispatch
    response = self.handle_exception(exc)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/rest_framework/views.py", line 455, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/rest_framework/views.py", line 492, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/d/Projects/le/develop/kolibri/core/device/api.py", line 93, in get
    instance_model = InstanceIDModel.get_or_create_current_instance()[0]
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/contextlib.py", line 74, in inner
    return func(*args, **kwds)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/morango/models/core.py", line 141, in get_or_create_current_instance
    current=False
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/query.py", line 650, in update
    rows = query.get_compiler(self.db).execute_sql(CURSOR)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1204, in execute_sql
    cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 899, in execute_sql
    raise original_exception
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 889, in execute_sql
    cursor.execute(sql, params)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/d/.pyenv/versions/3.7.6/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: database is locked

Steps to reproduce

This was observed both on the importing device and the exporting device.

Context

0.14.0 beta 3

rtibbles commented 4 years ago

Looks like the get_or_create is trying to pre-emptively be able to write even if it might not need to? (at this point, the instance ID should already be defined).

jamalex commented 4 years ago

Does it take some time to return, or does it return immediately?

I don't think it's actually to do with the instance ID not being defined, I think it could be possible for this to happen even with it being a read, given the strict read isolation that is necessary in order to maintain snapshot consistency for Morango operations. We recently increased the read isolation level for Postgres, as it defaults to a low level of consistency. SQLite already defaults to the highest level of consistency based on how it's architected, so nothing changed there.

The main thing going on here is the import of a massive set of demo facility data. The transactions while doing a transfer should be short enough, but the serialization/deserialization stages likely involve some very long-running transactions. Would be good to know whether this would have occurred in previous versions, or if there's an interaction with the changes recently made to the InstanceID stuff.

rtibbles commented 4 years ago

If it's just being read then it shouldn't get a database locked error though, that's why I was wondering exactly what might be happening internally. It should only error that the database is locked when the large write transaction is open for syncing, and then the call to get the instance ID ends up in a write to the DB.

bjester commented 4 years ago

I split up the push and pull sync operations into separate client classes with consistent API's so we can use the write lock on the sensitive portion(s) only; push initialization and pull finalization. Here's the WIP PR, still need to add a few more tests https://github.com/learningequality/morango/pull/85

nucleogenesis commented 4 years ago

Closed with above merges.