Commit f1401674 by muhammad-ammar

test ospr 91

parent a6c0d3a0
language: python
python:
- '2.7'
- '3.6'
env:
- TOXENV=django18
- TOXENV=django110
......
......@@ -10,21 +10,21 @@ Retrieve all profiles for a video with `edx_video_id`="example"
Returns (dict):
{
'url' : '/edxval/videos/example',
'edx_video_id': u'example',
'edx_video_id': 'example',
'duration': 111.0,
'client_video_id': u'The example video',
'client_video_id': 'The example video',
'encoded_videos': [
{
'url': u'http://www.example.com/example_mobile_video.mp4',
'url': 'http://www.example.com/example_mobile_video.mp4',
'file_size': 25556,
'bitrate': 9600,
'profile': u'mobile'
'profile': 'mobile'
},
{
'url': u'http://www.example.com/example_desktop_video.mp4',
'url': 'http://www.example.com/example_desktop_video.mp4',
'file_size': 43096734,
'bitrate': 64000,
'profile': u'desktop'
'profile': 'desktop'
}
]
}
......
"""
Admin file for django app edxval.
"""
from __future__ import unicode_literals
from django.contrib import admin
from .models import (CourseVideo, EncodedVideo, Profile, TranscriptPreference,
......
......@@ -3,6 +3,7 @@
"""
The internal API for VAL.
"""
from __future__ import unicode_literals
import logging
from enum import Enum
......@@ -10,14 +11,26 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from lxml import etree
from lxml.etree import Element, SubElement
from edxval.exceptions import (InvalidTranscriptFormat,
InvalidTranscriptProvider, ValCannotCreateError,
ValCannotUpdateError, ValInternalError,
ValVideoNotFoundError)
from edxval.models import (CourseVideo, EncodedVideo, Profile,
TranscriptFormat, TranscriptPreference,
TranscriptProviderType, Video, VideoImage,
VideoTranscript, ThirdPartyTranscriptCredentialsState)
from edxval.exceptions import (
InvalidTranscriptFormat,
InvalidTranscriptProvider,
ValCannotCreateError,
ValCannotUpdateError,
ValInternalError,
ValVideoNotFoundError,
)
from edxval.models import (
CourseVideo,
EncodedVideo,
Profile,
TranscriptFormat,
TranscriptPreference,
TranscriptProviderType,
Video,
VideoImage,
VideoTranscript,
ThirdPartyTranscriptCredentialsState,
)
from edxval.serializers import TranscriptPreferenceSerializer, TranscriptSerializer, VideoSerializer
from edxval.utils import THIRD_PARTY_TRANSCRIPTION_PLANS
......@@ -423,7 +436,7 @@ def update_video_image(edx_video_id, course_id, image_data, file_name):
course_id=course_id, video__edx_video_id=edx_video_id
)
except ObjectDoesNotExist:
error_message = u'VAL: CourseVideo not found for edx_video_id: {0} and course_id: {1}'.format(
error_message = 'VAL: CourseVideo not found for edx_video_id: {0} and course_id: {1}'.format(
edx_video_id,
course_id
)
......@@ -503,15 +516,15 @@ def get_video_info(edx_video_id):
Returns (dict):
{
'url' : '/edxval/videos/example',
'edx_video_id': u'example',
'edx_video_id': 'example',
'duration': 111.0,
'client_video_id': u'The example video',
'client_video_id': 'The example video',
'encoded_videos': [
{
'url': u'http://www.example.com',
'url': 'http://www.example.com',
'file_size': 25556,
'bitrate': 9600,
'profile': u'mobile'
'profile': 'mobile'
}
]
}
......@@ -590,7 +603,7 @@ def get_videos_for_course(course_id, sort_field=None, sort_dir=SortDirection.asc
total order.
"""
return _get_videos_for_filter(
{'courses__course_id': unicode(course_id), 'courses__is_hidden': False},
{'courses__course_id': course_id, 'courses__is_hidden': False},
sort_field,
sort_dir,
)
......@@ -658,28 +671,28 @@ def get_video_info_for_course_and_profiles(course_id, profiles):
Example:
Given two videos with two profiles each in course_id 'test_course':
{
u'edx_video_id_1': {
u'duration: 1111,
u'profiles': {
u'mobile': {
'url': u'http: //www.example.com/meow',
'edx_video_id_1': {
'duration: 1111,
'profiles': {
'mobile': {
'url': 'http: //www.example.com/meow',
'file_size': 2222
},
u'desktop': {
'url': u'http: //www.example.com/woof',
'desktop': {
'url': 'http: //www.example.com/woof',
'file_size': 4444
}
}
},
u'edx_video_id_2': {
u'duration: 2222,
u'profiles': {
u'mobile': {
'url': u'http: //www.example.com/roar',
'edx_video_id_2': {
'duration: 2222,
'profiles': {
'mobile': {
'url': 'http: //www.example.com/roar',
'file_size': 6666
},
u'desktop': {
'url': u'http: //www.example.com/bzzz',
'desktop': {
'url': 'http: //www.example.com/bzzz',
'file_size': 8888
}
}
......@@ -687,7 +700,6 @@ def get_video_info_for_course_and_profiles(course_id, profiles):
}
"""
# In case someone passes in a key (VAL doesn't really understand opaque keys)
course_id = unicode(course_id)
try:
encoded_videos = EncodedVideo.objects.filter(
profile__profile_name__in=profiles,
......@@ -729,7 +741,7 @@ def copy_course_videos(source_course_id, destination_course_id):
return
course_videos = CourseVideo.objects.select_related('video', 'video_image').filter(
course_id=unicode(source_course_id)
course_id=str(source_course_id)
)
for course_video in course_videos:
......@@ -785,7 +797,7 @@ def export_to_xml(video_ids, course_id=None, external=False):
'video_asset',
attrib={
'client_video_id': video.client_video_id,
'duration': unicode(video.duration),
'duration': str(video.duration),
'image': video_image_name
}
)
......@@ -794,7 +806,7 @@ def export_to_xml(video_ids, course_id=None, external=False):
video_el,
'encoded_video',
{
name: unicode(getattr(encoded_video, name))
name: str(getattr(encoded_video, name))
for name in ['profile', 'url', 'file_size', 'bitrate']
}
)
......@@ -879,7 +891,7 @@ def import_from_xml(xml, edx_video_id, course_id=None):
return
except ValidationError as err:
logger.exception(err.message)
logger.exception(err)
raise ValCannotCreateError(err.message_dict)
except Video.DoesNotExist:
pass
......
"""
VAL Exceptions.
"""
from __future__ import unicode_literals
class ValError(Exception):
"""
......
......@@ -35,7 +35,7 @@ class Migration(migrations.Migration):
name='Profile',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('profile_name', models.CharField(unique=True, max_length=50, validators=[django.core.validators.RegexValidator(regex=b'^[a-zA-Z0-9\\-_]*$', message=b'profile_name has invalid characters', code=b'invalid profile_name')])),
('profile_name', models.CharField(unique=True, max_length=50, validators=[django.core.validators.RegexValidator(regex='^[a-zA-Z0-9\\-_]*$', message=b'profile_name has invalid characters', code=b'invalid profile_name')])),
],
),
migrations.CreateModel(
......@@ -54,7 +54,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', models.DateTimeField(auto_now_add=True)),
('edx_video_id', models.CharField(unique=True, max_length=100, validators=[django.core.validators.RegexValidator(regex=b'^[a-zA-Z0-9\\-_]*$', message=b'edx_video_id has invalid characters', code=b'invalid edx_video_id')])),
('edx_video_id', models.CharField(unique=True, max_length=100, validators=[django.core.validators.RegexValidator(regex='^[a-zA-Z0-9\\-_]*$', message=b'edx_video_id has invalid characters', code=b'invalid edx_video_id')])),
('client_video_id', models.CharField(db_index=True, max_length=255, blank=True)),
('duration', models.FloatField(validators=[django.core.validators.MinValueValidator(0)])),
('status', models.CharField(max_length=255, db_index=True)),
......
......@@ -11,6 +11,7 @@ themselves. After these are resolved, errors such as a negative file_size or
invalid profile_name will be returned.
"""
from __future__ import unicode_literals
import json
import logging
import os
......@@ -22,7 +23,7 @@ from django.core.urlresolvers import reverse
from django.core.validators import MinValueValidator, RegexValidator
from django.db import models
from django.dispatch import receiver
from django.utils.six import python_2_unicode_compatible
from django.utils.six import python_2_unicode_compatible, string_types
from model_utils.models import TimeStampedModel
from edxval.utils import (get_video_image_storage,
......@@ -219,7 +220,7 @@ class ListField(models.TextField):
Converts a list to its json representation to store in database as text.
"""
if value and not isinstance(value, list):
raise ValidationError(u'ListField value {} is not a list.'.format(value))
raise ValidationError('ListField value {} is not a list.'.format(value))
return json.dumps(self.validate_list(value) or [])
def from_db_value(self, value, expression, connection, context):
......@@ -247,7 +248,7 @@ class ListField(models.TextField):
self.validate_list(py_list)
except (ValueError, TypeError):
raise ValidationError(u'Must be a valid list of strings.')
raise ValidationError('Must be a valid list of strings.')
return py_list
......@@ -265,12 +266,10 @@ class ListField(models.TextField):
ValidationError
"""
if len(value) > self.max_items:
raise ValidationError(
u'list must not contain more than {max_items} items.'.format(max_items=self.max_items)
)
raise ValidationError('list must not contain more than {max_items} items.'.format(max_items=self.max_items))
if all(isinstance(item, basestring) for item in value) is False:
raise ValidationError(u'list must only contain strings.')
if all(isinstance(item, string_types) for item in value) is False:
raise ValidationError('list must only contain strings.')
return value
......
......@@ -4,6 +4,7 @@ Serializers for Video Abstraction Layer
Serialization is usually sent through the VideoSerializer which uses the
EncodedVideoSerializer which uses the profile_name as it's profile field.
"""
from __future__ import unicode_literals
from rest_framework import serializers
from rest_framework.fields import DateTimeField, IntegerField
......
"""
Settings file for django app edxval.
"""
from __future__ import unicode_literals
DEBUG = True
TEMPLATE_DEBUG = DEBUG
......
# pylint: disable=E1103, W0105
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
"""
Constants used for tests.
"""
......
......@@ -4,6 +4,7 @@
Tests the serializers for the Video Abstraction Layer
"""
from __future__ import unicode_literals
from django.test import TestCase
from edxval.serializers import EncodedVideoSerializer, VideoSerializer
......@@ -152,7 +153,9 @@ class SerializerTests(TestCase):
data = "hello"
serializer = VideoSerializer(data=data)
self.assertFalse(serializer.is_valid())
data_type = type(data).__name__
self.assertEqual(
serializer.errors.get("non_field_errors")[0],
"Invalid data. Expected a dictionary, but got str."
"Invalid data. Expected a dictionary, but got {}.".format(data_type)
)
......@@ -2,6 +2,7 @@
"""
Tests for Video Abstraction Layer views
"""
from __future__ import unicode_literals
import json
import unittest
......@@ -446,7 +447,7 @@ class VideoListTest(APIAuthTestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response = json.loads(response.content)
# Check that invalid course keys have been filtered out.
self.assertEqual(response['courses'], [{u'edX/DemoX/Astonomy': None}])
self.assertEqual(response['courses'], [{'edX/DemoX/Astonomy': None}])
def test_post_non_latin_client_video_id(self):
"""
......@@ -475,7 +476,7 @@ class VideoListTest(APIAuthTestCase):
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data.get("edx_video_id")[0],
u'video with this edx video id already exists.'
'video with this edx video id already exists.'
)
videos = len(self.client.get("/edxval/videos/").data)
self.assertEqual(videos, 1)
......@@ -764,19 +765,19 @@ class VideoImagesViewTest(APIAuthTestCase):
@data(
{
'post_data': {},
'message': u'course_id and edx_video_id and generated_images must be specified to update a video image.'
'message': 'course_id and edx_video_id and generated_images must be specified to update a video image.'
},
{
'post_data': {'course_id': 'does_not_exit_course', 'edx_video_id': 'super-soaker', 'generated_images': []},
'message': u'CourseVideo not found for course_id: does_not_exit_course'
'message': 'CourseVideo not found for course_id: does_not_exit_course'
},
{
'post_data': {'course_id': 'test_course_id', 'edx_video_id': 'does_not_exit_video', 'generated_images': []},
'message': u'CourseVideo not found for course_id: test_course_id'
'message': 'CourseVideo not found for course_id: test_course_id'
},
{
'post_data': {'course_id': 'test_course_id', 'edx_video_id': 'super-soaker', 'generated_images': [1, 2, 3]},
'message': "[u'list must only contain strings.']"
'message': "'list must only contain strings.'"
},
)
@unpack
......@@ -788,9 +789,9 @@ class VideoImagesViewTest(APIAuthTestCase):
response = self.client.post(url, post_data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data['message'],
message
self.assertIn(
message,
response.data['message']
)
......
"""
Url file for django app edxval.
"""
from __future__ import unicode_literals
from django.conf.urls import url
......
......@@ -2,6 +2,8 @@
Util methods to be used in api and models.
"""
from __future__ import unicode_literals
from django.conf import settings
from django.core.files.storage import get_storage_class
......@@ -128,7 +130,7 @@ def video_image_path(video_image_instance, filename): # pylint:disable=unused-a
video_image_instance (VideoImage): This is passed automatically by models.CustomizableImageField
filename (str): name of image file
"""
return u'{}{}'.format(settings.VIDEO_IMAGE_SETTINGS.get('DIRECTORY_PREFIX', ''), filename)
return '{}{}'.format(settings.VIDEO_IMAGE_SETTINGS.get('DIRECTORY_PREFIX', ''), filename)
def get_video_image_storage():
......
"""
Views file for django app edxval.
"""
from __future__ import unicode_literals
import logging
from django.core.exceptions import ValidationError
......@@ -229,7 +231,7 @@ class VideoImagesView(APIView):
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={
'message': u'{missing} must be specified to update a video image.'.format(
'message': '{missing} must be specified to update a video image.'.format(
missing=' and '.join(missing)
)
}
......@@ -241,12 +243,13 @@ class VideoImagesView(APIView):
try:
course_video = CourseVideo.objects.select_related('video_image').get(
course_id=unicode(course_id), video__edx_video_id=edx_video_id
course_id=course_id,
video__edx_video_id=edx_video_id
)
except CourseVideo.DoesNotExist:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={'message': u'CourseVideo not found for course_id: {course_id}'.format(course_id=course_id)}
data={'message': 'CourseVideo not found for course_id: {course_id}'.format(course_id=course_id)}
)
try:
......
-e git+https://github.com/edx/django-oauth2-provider.git@0.2.7-fork-edx-6a#egg=django-oauth2-provider==0.2.7-fork-edx-6
-e git+https://github.com/edx/django-rest-framework-oauth.git@f0b503fda8c254a38f97fef802ded4f5fe367f7a#egg=djangorestframework-oauth
-e git+https://github.com/edx/django-oauth2-provider.git@1.2.2#egg=django-oauth2-provider==1.2.2
-e git+https://github.com/edx/django-rest-framework-oauth.git@392d3b423788718c04e7aab8dba17a56f95d757f#egg=djangorestframework-oauth
pillow==4.2.1
boto==2.46.1
django-model-utils==2.3.1
......
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment