docs: def _prepare_context(self, data_id, data_dir, runtime_dir, **kwargs):
          """Prepare settings and constants JSONs for the executor.
  
          Settings and constants provided by other ``resolwe`` modules and
          :class:`~django.conf.settings` are all inaccessible in the
          executor once it is deployed, so they need to be serialized into
          the runtime directory.
  
          :param data_id: The :class:`~resolwe.flow.models.Data` object id
              being prepared for.
          :param data_dir: The target execution directory for this
              :class:`~resolwe.flow.models.Data` object.
          :param runtime_dir: The target runtime support directory for
              this :class:`~resolwe.flow.models.Data` object; this is
              where the environment is serialized into.
          :param kwargs: Extra settings to include in the main settings
              file.
          """
          files = {}
          secrets = {}
  
          settings_dict = {}
          settings_dict['DATA_DIR'] = data_dir
          settings_dict['REDIS_CHANNEL_PAIR'] = state.MANAGER_EXECUTOR_CHANNELS
          files[ExecutorFiles.EXECUTOR_SETTINGS] = settings_dict
  
          django_settings = {}
          django_settings.update(self.settings_actual)
          django_settings.update(kwargs)
          files[ExecutorFiles.DJANGO_SETTINGS] = django_settings
  
          # Add scheduling classes.
          files[ExecutorFiles.PROCESS_META] = {
              k: getattr(Process, k) for k in dir(Process)
              if k.startswith('SCHEDULING_CLASS_') and isinstance(getattr(Process, k), str)
          }
  
          # Add Data status constants.
          files[ExecutorFiles.DATA_META] = {
              k: getattr(Data, k) for k in dir(Data)
              if k.startswith('STATUS_') and isinstance(getattr(Data, k), str)
          }
  
          # Extend the settings with whatever the executor wants.
          self.executor.extend_settings(data_id, files, secrets)
  
          # Save the settings into the various files in the runtime dir.
          settings_dict[ExecutorFiles.FILE_LIST_KEY] = list(files.keys())
          for file_name in files:
              file_path = os.path.join(runtime_dir, file_name)
              with open(file_path, 'wt') as json_file:
                  json.dump(files[file_name], json_file, cls=SettingsJSONifier)
  
          # Save the secrets in the runtime dir, with permissions to prevent listing the given
          # directory.
          secrets_dir = os.path.join(runtime_dir, ExecutorFiles.SECRETS_DIR)
          os.makedirs(secrets_dir, mode=0o300)
          for file_name, value in secrets.items():
              file_path = os.path.join(secrets_dir, file_name)
  
              # Set umask to 0 to ensure that we set the correct permissions.
              old_umask = os.umask(0)
              try:
                  # We need to use os.open in order to correctly enforce file creation. Otherwise,
                  # there is a race condition which can be used to create the file with different
                  # ownership/permissions.
                  file_descriptor = os.open(file_path, os.O_WRONLY | os.O_CREAT, mode=0o600)
                  with os.fdopen(file_descriptor, 'w') as raw_file:
                      raw_file.write(value)
              finally:
                  os.umask(old_umask)