From 66d257584cb69158c1b30fb39526abae673b0d68 Mon Sep 17 00:00:00 2001 From: Philip ABBET <philip.abbet@idiap.ch> Date: Tue, 15 Nov 2016 09:42:50 +0100 Subject: [PATCH] [algorithms, api] Add support for creating binary algorithms --- beat/web/algorithms/models.py | 9 ++- beat/web/algorithms/tests/core.py | 3 + beat/web/algorithms/tests/tests_api.py | 78 ++++++++++++++++++++++++-- beat/web/code/models.py | 16 ++++-- beat/web/code/serializers.py | 10 +++- 5 files changed, 100 insertions(+), 16 deletions(-) mode change 100644 => 100755 beat/web/algorithms/models.py diff --git a/beat/web/algorithms/models.py b/beat/web/algorithms/models.py old mode 100644 new mode 100755 index 28864f022..9e9b90648 --- a/beat/web/algorithms/models.py +++ b/beat/web/algorithms/models.py @@ -93,13 +93,13 @@ class AlgorithmStorage(OverwriteStorage): class AlgorithmManager(CodeManager): def create_algorithm(self, author, name, short_description='', - description='', declaration=None, code=None, version=1, - previous_version=None, fork_of=None): + description='', declaration=None, language=None, code=None, + version=1, previous_version=None, fork_of=None): default = beat.core.algorithm.Algorithm(settings.PREFIX, data=None) return self.create_code(author, name, default, short_description, - description, declaration, code, version, + description, declaration, language, code, version, previous_version, fork_of) @@ -307,6 +307,9 @@ class Algorithm(Code): def deletable(self): return (self.experiments.count() == 0) and super(Algorithm, self).deletable() + def valid(self): + return (self.source_code_file.name is not None) and (self.source_code_file.name != '') + def core(self): return validate_algorithm(self.declaration) diff --git a/beat/web/algorithms/tests/core.py b/beat/web/algorithms/tests/core.py index ed684d664..8bebec3fe 100755 --- a/beat/web/algorithms/tests/core.py +++ b/beat/web/algorithms/tests/core.py @@ -320,10 +320,13 @@ class AlgorithmsTestCase(AlgorithmsBaseTestCase): declaration=declaration, ) assert algorithm, errors + assert not algorithm.valid() algorithm.source_code = binary_data algorithm.save() + assert algorithm.valid() + # Usable by one user (algorithm, errors) = Algorithm.objects.create_algorithm( author=user1, diff --git a/beat/web/algorithms/tests/tests_api.py b/beat/web/algorithms/tests/tests_api.py index 5604c781c..1bff20107 100755 --- a/beat/web/algorithms/tests/tests_api.py +++ b/beat/web/algorithms/tests/tests_api.py @@ -35,6 +35,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from ...dataformats.models import DataFormat from ...common.testutils import tearDownModule +from ...code.models import Code import beat.core.algorithm @@ -561,14 +562,17 @@ class AlgorithmCreation(AlgorithmsAPIBase): "declaration (beyond white spaces): %r != %r" % \ (in_storage, expected) - # set storage language so it can find the code - storage.language = in_storage['language'] + if in_storage['language'] == 'python': + self.assertTrue(algorithm.valid()) - in_storage = storage.code.try_load() - expected = code + # set storage language so it can find the code + storage.language = in_storage['language'] - assert in_storage == expected, "There are differences on the " \ - "code: %r != %r" % (in_storage, expected) + in_storage = storage.code.try_load() + expected = code + + assert in_storage == expected, "There are differences on the " \ + "code: %r != %r" % (in_storage, expected) def test_no_creation_for_anonymous_user(self): @@ -919,6 +923,68 @@ class AlgorithmCreation(AlgorithmsAPIBase): self.checkResponse(response, 400, content_type='application/json') + def test_cxx_algorithm_using_declaration(self): + self.client.login(username='jackdoe', password='1234') + + response = self.client.post(self.url, + json.dumps({ + 'name': 'valid-name1', + 'description': 'blah', + 'declaration':AlgorithmsAPIBase.CXX_DECLARATION, + }), content_type='application/json') + + url = reverse('api_algorithms:object', args=['jackdoe', 'valid-name1', 1]) + content = self.checkResponse(response, 201, + content_type='application/json', + location=url) + + self.assertTrue(isinstance(content, dict)) + self.assertEqual(content['name'], 'valid-name1') + self.assertTrue(content['url'].endswith(url)) + + try: + algorithm = Algorithm.objects.get(author__username='jackdoe', name='valid-name1') + except: + self.assertTrue(False) + + self.assertEqual(algorithm.short_description, '') + self.assertEqual(algorithm.description, 'blah') + self.assertEqual(algorithm.language, Code.CXX) + self.assertFalse(algorithm.valid()) + self.checkAlgorithm(algorithm, declaration=AlgorithmsAPIBase.CXX_DECLARATION, code=None) + + + def test_cxx_algorithm_using_language(self): + self.client.login(username='jackdoe', password='1234') + + response = self.client.post(self.url, + json.dumps({ + 'name': 'valid-name1', + 'description': 'blah', + 'language': 'cxx', + }), content_type='application/json') + + url = reverse('api_algorithms:object', args=['jackdoe', 'valid-name1', 1]) + content = self.checkResponse(response, 201, + content_type='application/json', + location=url) + + self.assertTrue(isinstance(content, dict)) + self.assertEqual(content['name'], 'valid-name1') + self.assertTrue(content['url'].endswith(url)) + + try: + algorithm = Algorithm.objects.get(author__username='jackdoe', name='valid-name1') + except: + self.assertTrue(False) + + self.assertEqual(algorithm.short_description, '') + self.assertEqual(algorithm.description, 'blah') + self.assertEqual(algorithm.language, Code.CXX) + self.assertFalse(algorithm.valid()) + + + class AlgorithmUpdate(AlgorithmsAPIBase): def setUp(self): super(AlgorithmUpdate, self).setUp() diff --git a/beat/web/code/models.py b/beat/web/code/models.py index 8131372e8..768e8c542 100755 --- a/beat/web/code/models.py +++ b/beat/web/code/models.py @@ -51,12 +51,14 @@ import simplejson class CodeManager(StoredContributionManager): def create_object(self, author, name, short_description='', description='', - declaration=None, code=None, version=1, previous_version=None, - fork_of=None): + declaration=None, language=None, code=None, version=1, + previous_version=None, fork_of=None): create = getattr(self, 'create_{}'.format(self.model.__name__.lower())) - return create(author=author, name=name, short_description=short_description, description=description, - declaration=declaration, code=code, version=version, previous_version=previous_version, fork_of=fork_of) + return create(author=author, name=name, short_description=short_description, + description=description, declaration=declaration, language=language, + code=code, version=version, previous_version=previous_version, + fork_of=fork_of) def for_user(self, user, add_public=False): if user.is_anonymous(): @@ -101,8 +103,8 @@ class CodeManager(StoredContributionManager): return objects_for_user.order_by('author__username', 'name', '-version').select_related() def create_code(self, author, name, default, short_description='', - description='', declaration=None, code=None, version=1, - previous_version=None, fork_of=None): + description='', declaration=None, language=None, code=None, + version=1, previous_version=None, fork_of=None): # Create the database representation code_db = self.model( @@ -122,6 +124,8 @@ class CodeManager(StoredContributionManager): declaration = fork_of.declaration else: declaration = default.data + if language is not None: + declaration['language'] = language elif not(isinstance(declaration, dict)): declaration = simplejson.loads(declaration) diff --git a/beat/web/code/serializers.py b/beat/web/code/serializers.py index b50d101f6..75569fe62 100755 --- a/beat/web/code/serializers.py +++ b/beat/web/code/serializers.py @@ -43,9 +43,17 @@ import difflib class CodeCreationSerializer(ContributionCreationSerializer): code = serializers.CharField(required=False, allow_blank=True, trim_whitespace=False) + language = serializers.CharField(required=False, allow_blank=True, trim_whitespace=False) class Meta(ContributionCreationSerializer.Meta): - fields = ContributionCreationSerializer.Meta.fields + ['code'] + fields = ContributionCreationSerializer.Meta.fields + ['code', 'language'] + + def validate_language(self, value): + try: + if len(filter(lambda x: x[1].lower() == value, iter(Code.CODE_LANGUAGE))) > 0: + return value + except: + raise serializers.ValidationError('Unsupported language: %s' % value) #---------------------------------------------------------- -- GitLab