Esempio n. 1
0
    def test_require_valid_name(self):
        name = 'name'
        utils.require_valid_name(name, 'name_type')

        name = 0
        with self.assertRaisesRegexp(Exception, '0 must be a string.'):
            utils.require_valid_name(name, 'name_type')
Esempio n. 2
0
    def validate(self):
        """Validates various properties of the Misconception object.

        Raises:
            ValidationError: One or more attributes of the misconception are
                invalid.
        """
        self.require_valid_misconception_id(self.id)
        if not isinstance(self.name, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected misconception name to be a string, received %s' %
                self.name)
        utils.require_valid_name(self.name,
                                 'misconception_name',
                                 allow_empty=False)

        if not isinstance(self.notes, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected misconception notes to be a string, received %s' %
                self.notes)

        if not isinstance(self.must_be_addressed, bool):
            raise utils.ValidationError(
                'Expected must_be_addressed to be a bool, received %s' %
                self.must_be_addressed)

        if not isinstance(self.feedback, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected misconception feedback to be a string, received %s' %
                self.feedback)
Esempio n. 3
0
    def test_require_valid_name(self):
        # type: () -> None
        name = 'name' # type: Any
        utils.require_valid_name(name, 'name_type')

        name = 0
        with self.assertRaisesRegexp(Exception, '0 must be a string.'): # type: ignore[no-untyped-call]
            utils.require_valid_name(name, 'name_type')
Esempio n. 4
0
    def test_require_valid_name(self) -> None:
        name = 'name'
        utils.require_valid_name(name, 'name_type')

        invalid_name = 0
        with self.assertRaisesRegexp(Exception, '0 must be a string.'): # type: ignore[no-untyped-call]
            # Type ignore is used below because we are providing integer
            # argument instead of string for invalid_name for testing purposes.
            utils.require_valid_name(invalid_name, 'name_type') # type: ignore[arg-type]
Esempio n. 5
0
    def validate(self):
        """Validates the classifier before it is saved to storage."""

        if not isinstance(self.id, basestring):
            raise utils.ValidationError(
                'Expected id to be a string, received %s' % self.id)

        if not isinstance(self.exp_id, basestring):
            raise utils.ValidationError(
                'Expected exp_id to be a string, received %s' % self.exp_id)

        if not isinstance(self.exp_version_when_created, int):
            raise utils.ValidationError(
                'Expected exp_version_when_created to be an int, received %s' %
                self.exp_version_when_created)

        if not isinstance(self.state_name, basestring):
            raise utils.ValidationError(
                'Expected id to be a string, received %s' % self.state_name)
        utils.require_valid_name(self.state_name, 'the state name')

        if not isinstance(self.algorithm_id, basestring):
            raise utils.ValidationError(
                'Expected algorithm_id to be a string, received %s' %
                self.algorithm_id)
        utils.require_valid_name(self.algorithm_id, 'the algorithm id')
        algorithm_ids = [
            classifier_details['algorithm_id'] for classifier_details in
            feconf.INTERACTION_CLASSIFIER_MAPPING.values()
        ]
        if self.algorithm_id not in algorithm_ids:
            raise utils.ValidationError('Invalid algorithm id: %s' %
                                        self.algorithm_id)

        if not isinstance(self.classifier_data, dict):
            raise utils.ValidationError(
                'Expected classifier_data to be a dict, received %s' %
                (self.classifier_data))
        classifier_class = (
            classifier_registry.Registry.get_classifier_by_algorithm_id(
                self.algorithm_id))
        classifier_class.validate(self.classifier_data)
Esempio n. 6
0
    def validate(self):
        """Validates the classifier before it is saved to storage."""

        if not isinstance(self.id, basestring):
            raise utils.ValidationError(
                'Expected id to be a string, received %s' % self.id)

        if not isinstance(self.exp_id, basestring):
            raise utils.ValidationError(
                'Expected exp_id to be a string, received %s' % self.exp_id)

        if not isinstance(self.exp_version_when_created, int):
            raise utils.ValidationError(
                'Expected exp_version_when_created to be a int, received %s' %
                self.exp_version_when_created)

        if not isinstance(self.state_name, basestring):
            raise utils.ValidationError(
                'Expected id to be a string, received %s' % self.state_name)
        utils.require_valid_name(self.state_name, 'the state name')

        if not isinstance(self.algorithm_id, basestring):
            raise utils.ValidationError(
                'Expected algorithm_id to be a string, received %s' %
                self.algorithm_id)
        utils.require_valid_name(
            self.algorithm_id, 'the algorithm id')
        if self.algorithm_id not in (
                feconf.INTERACTION_CLASSIFIER_MAPPING.values()):
            raise utils.ValidationError(
                'Invalid algorithm id: %s' % self.algorithm_id)

        if not isinstance(self.cached_classifier_data, dict):
            raise utils.ValidationError(
                'Expected cached_classifier_data to be a dict, received %s' %(
                    self.cached_classifier_data))
        classifier_class = (
            classifier_registry.Registry.get_classifier_by_algorithm_id(
                self.algorithm_id))
        classifier_class.validate(self.cached_classifier_data)
Esempio n. 7
0
    def validate(self, strict=True):
        """Validates all properties of this collection and its constituents."""

        if not isinstance(self.title, basestring):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(self.title, 'the collection title')

        if not isinstance(self.category, basestring):
            raise utils.ValidationError(
                'Expected category to be a string, received %s'
                % self.category)
        utils.require_valid_name(self.category, 'the collection category')

        if not isinstance(self.objective, basestring):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not self.objective:
            raise utils.ValidationError(
                'An objective must be specified (in the \'Settings\' tab).')

        if not isinstance(self.schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.schema_version)

        if self.schema_version != feconf.CURRENT_COLLECTION_SCHEMA_VERSION:
            raise utils.ValidationError(
                'Expected schema version to be %s, received %s' % (
                    feconf.CURRENT_COLLECTION_SCHEMA_VERSION,
                    self.schema_version))

        if not isinstance(self.nodes, list):
            raise utils.ValidationError(
                'Expected nodes to be a list, received %s' % self.nodes)

        all_exp_ids = self.exploration_ids
        if len(set(all_exp_ids)) != len(all_exp_ids):
            raise utils.ValidationError(
                'There are explorations referenced in the collection more '
                'than once.')

        # Validate all collection nodes.
        for node in self.nodes:
            node.validate()

        if strict:
            if not self.nodes:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration in the '
                    'collection.')

            # Ensure the collection may be started.
            if not self.init_exploration_ids:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration with no '
                    'prerequisite skills.')

            # Ensure the collection can be completed. This is done in two
            # steps: first, no exploration may grant a skill that it
            # simultaneously lists as a prerequisite. Second, every exploration
            # in the collection must be reachable when starting from the
            # explorations with no prerequisite skills and playing through all
            # subsequent explorations provided by get_next_exploration_ids.
            completed_exp_ids = set(self.init_exploration_ids)
            next_exp_ids = self.get_next_exploration_ids(
                list(completed_exp_ids))
            while next_exp_ids:
                completed_exp_ids.update(set(next_exp_ids))
                next_exp_ids = self.get_next_exploration_ids(
                    list(completed_exp_ids))

            if len(completed_exp_ids) != len(self.nodes):
                unreachable_ids = set(all_exp_ids) - completed_exp_ids
                raise utils.ValidationError(
                    'Some explorations are unreachable from the initial '
                    'explorations: %s' % unreachable_ids)
    def validate(self, strict=True):
        """Validates all properties of this collection and its constituents.

        Raises:
            ValidationError: One or more attributes of the Collection are not
            valid.
        """

        # NOTE TO DEVELOPERS: Please ensure that this validation logic is the
        # same as that in the frontend CollectionValidatorService.

        if not isinstance(self.title, basestring):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(self.title,
                                 'the collection title',
                                 allow_empty=True)

        if not isinstance(self.category, basestring):
            raise utils.ValidationError(
                'Expected category to be a string, received %s' %
                self.category)
        utils.require_valid_name(self.category,
                                 'the collection category',
                                 allow_empty=True)

        if not isinstance(self.objective, basestring):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not self.language_code:
            raise utils.ValidationError(
                'A language must be specified (in the \'Settings\' tab).')

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        # TODO(sll): Remove this check once App Engine supports 3-letter
        # language codes in search.
        if len(self.language_code) != 2:
            raise utils.ValidationError(
                'Invalid language_code, it should have exactly 2 letters: %s' %
                self.language_code)

        if not isinstance(self.tags, list):
            raise utils.ValidationError(
                'Expected tags to be a list, received %s' % self.tags)

        if len(set(self.tags)) < len(self.tags):
            raise utils.ValidationError(
                'Expected tags to be unique, but found duplicates')

        for tag in self.tags:
            if not isinstance(tag, basestring):
                raise utils.ValidationError(
                    'Expected each tag to be a string, received \'%s\'' % tag)

            if not tag:
                raise utils.ValidationError('Tags should be non-empty.')

            if not re.match(feconf.TAG_REGEX, tag):
                raise utils.ValidationError(
                    'Tags should only contain lowercase letters and spaces, '
                    'received \'%s\'' % tag)

            if (tag[0] not in string.ascii_lowercase
                    or tag[-1] not in string.ascii_lowercase):
                raise utils.ValidationError(
                    'Tags should not start or end with whitespace, received '
                    ' \'%s\'' % tag)

            if re.search(r'\s\s+', tag):
                raise utils.ValidationError(
                    'Adjacent whitespace in tags should be collapsed, '
                    'received \'%s\'' % tag)

        if not isinstance(self.schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.schema_version)

        if self.schema_version != feconf.CURRENT_COLLECTION_SCHEMA_VERSION:
            raise utils.ValidationError(
                'Expected schema version to be %s, received %s' %
                (feconf.CURRENT_COLLECTION_SCHEMA_VERSION,
                 self.schema_version))

        if not isinstance(self.nodes, list):
            raise utils.ValidationError(
                'Expected nodes to be a list, received %s' % self.nodes)

        all_exp_ids = self.exploration_ids
        if len(set(all_exp_ids)) != len(all_exp_ids):
            raise utils.ValidationError(
                'There are explorations referenced in the collection more '
                'than once.')

        # Validate all collection nodes.
        for node in self.nodes:
            node.validate()

        if strict:
            if not self.title:
                raise utils.ValidationError(
                    'A title must be specified for the collection.')

            if not self.objective:
                raise utils.ValidationError(
                    'An objective must be specified for the collection.')

            if not self.category:
                raise utils.ValidationError(
                    'A category must be specified for the collection.')

            if not self.nodes:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration in the '
                    'collection.')

            # Ensure the collection may be started.
            if not self.first_exploration_id:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration.')
Esempio n. 9
0
    def validate(self):
        """Validates the training job before it is saved to storage."""

        algorithm_ids = []
        if not isinstance(self.job_id, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected id to be a string, received %s' % self.job_id)

        if not isinstance(self.exp_id, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected exp_id to be a string, received %s' % self.exp_id)

        if not isinstance(self.exp_version, int):
            raise utils.ValidationError(
                'Expected exp_version to be an int, received %s' %
                self.exp_version)

        if not isinstance(self.next_scheduled_check_time, datetime.datetime):
            raise utils.ValidationError(
                'Expected next_scheduled_check_time to be datetime,' +
                ' received %s' % self.next_scheduled_check_time)

        if not isinstance(self.state_name, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected state to be a string, received %s' % self.state_name)
        utils.require_valid_name(self.state_name, 'the state name')

        if self.status not in feconf.ALLOWED_TRAINING_JOB_STATUSES:
            raise utils.ValidationError(
                'Expected status to be in %s, received %s' %
                (feconf.ALLOWED_TRAINING_JOB_STATUSES, self.status))

        if not isinstance(self.interaction_id, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected interaction_id to be a string, received %s' %
                self.interaction_id)

        if self.interaction_id not in feconf.INTERACTION_CLASSIFIER_MAPPING:
            raise utils.ValidationError('Invalid interaction id: %s' %
                                        self.interaction_id)

        if not isinstance(self.algorithm_id, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected algorithm_id to be a string, received %s' %
                self.algorithm_id)

        algorithm_ids = [
            classifier_details['algorithm_id'] for classifier_details in
            feconf.INTERACTION_CLASSIFIER_MAPPING.values()
        ]
        if self.algorithm_id not in algorithm_ids:
            raise utils.ValidationError('Invalid algorithm id: %s' %
                                        self.algorithm_id)

        if not isinstance(self.training_data, list):
            raise utils.ValidationError(
                'Expected training_data to be a list, received %s' %
                (self.training_data))

        for grouped_answers in self.training_data:
            if 'answer_group_index' not in grouped_answers:
                raise utils.ValidationError(
                    'Expected answer_group_index to be a key in training_data'
                    'list item')
            if 'answers' not in grouped_answers:
                raise utils.ValidationError(
                    'Expected answers to be a key in training_data list item')
            if not isinstance(grouped_answers['answer_group_index'], int):
                raise utils.ValidationError(
                    'Expected answer_group_index to be an int, received %s' %
                    grouped_answers['answer_group_index'])
            if not isinstance(grouped_answers['answers'], list):
                raise utils.ValidationError(
                    'Expected answers to be a list, received %s' %
                    grouped_answers['answers'])

        # Classifier data can be either None (before its stored) or a dict.
        if not isinstance(self.classifier_data, dict) and self.classifier_data:
            raise utils.ValidationError(
                'Expected classifier_data to be a dict|None, received %s' %
                (self.classifier_data))

        if not isinstance(self.data_schema_version, int):
            raise utils.ValidationError(
                'Expected data_schema_version to be an int, received %s' %
                self.data_schema_version)
Esempio n. 10
0
    def validate(self, strict=True):
        """Validates all properties of this collection and its constituents."""

        if not isinstance(self.title, basestring):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(self.title, 'the collection title')

        if not isinstance(self.category, basestring):
            raise utils.ValidationError(
                'Expected category to be a string, received %s'
                % self.category)
        utils.require_valid_name(self.category, 'the collection category')

        if not isinstance(self.objective, basestring):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not self.objective:
            raise utils.ValidationError(
                'An objective must be specified (in the \'Settings\' tab).')

        if not isinstance(self.schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.schema_version)

        if self.schema_version != feconf.CURRENT_COLLECTION_SCHEMA_VERSION:
            raise utils.ValidationError(
                'Expected schema version to be %s, received %s' % (
                    feconf.CURRENT_COLLECTION_SCHEMA_VERSION,
                    self.schema_version))

        if not isinstance(self.nodes, list):
            raise utils.ValidationError(
                'Expected nodes to be a list, received %s' % self.nodes)

        all_exp_ids = self.exploration_ids
        if len(set(all_exp_ids)) != len(all_exp_ids):
            raise utils.ValidationError(
                'There are explorations referenced in the collection more '
                'than once.')

        # Validate all collection nodes.
        for node in self.nodes:
            node.validate()

        if strict:
            if not self.nodes:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration in the '
                    'collection.')

            # Ensure the collection may be started.
            if not self.init_exploration_ids:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration with no '
                    'prerequisite skills.')

            # Ensure the collection can be completed. This is done in two
            # steps: first, no exploration may grant a skill that it
            # simultaneously lists as a prerequisite. Second, every exploration
            # in the collection must be reachable when starting from the
            # explorations with no prerequisite skills and playing through all
            # subsequent explorations provided by get_next_exploration_ids.
            completed_exp_ids = set(self.init_exploration_ids)
            next_exp_ids = self.get_next_exploration_ids(
                list(completed_exp_ids))
            while next_exp_ids:
                completed_exp_ids.update(set(next_exp_ids))
                next_exp_ids = self.get_next_exploration_ids(
                    list(completed_exp_ids))

            if len(completed_exp_ids) != len(self.nodes):
                unreachable_ids = set(all_exp_ids) - completed_exp_ids
                raise utils.ValidationError(
                    'Some explorations are unreachable from the initial '
                    'explorations: %s' % unreachable_ids)
Esempio n. 11
0
    def validate(self):
        """Validates various properties of the CollectionSummary.

        Raises:
            ValidationError. One or more attributes of the CollectionSummary
                are invalid.
        """
        if not isinstance(self.title, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(
            self.title, 'the collection title', allow_empty=True)

        if not isinstance(self.category, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected category to be a string, received %s'
                % self.category)
        utils.require_valid_name(
            self.category, 'the collection category', allow_empty=True)

        if not isinstance(self.objective, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not self.language_code:
            raise utils.ValidationError(
                'A language must be specified (in the \'Settings\' tab).')

        if not isinstance(self.language_code, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not utils.is_valid_language_code(self.language_code):
            raise utils.ValidationError(
                'Invalid language code: %s' % self.language_code)

        if not isinstance(self.tags, list):
            raise utils.ValidationError(
                'Expected tags to be a list, received %s' % self.tags)

        for tag in self.tags:
            if not isinstance(tag, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each tag to be a string, received \'%s\'' % tag)

            if not tag:
                raise utils.ValidationError('Tags should be non-empty.')

            if not re.match(constants.TAG_REGEX, tag):
                raise utils.ValidationError(
                    'Tags should only contain lowercase letters and spaces, '
                    'received \'%s\'' % tag)

            if (tag[0] not in string.ascii_lowercase or
                    tag[-1] not in string.ascii_lowercase):
                raise utils.ValidationError(
                    'Tags should not start or end with whitespace, received '
                    '\'%s\'' % tag)

            if re.search(r'\s\s+', tag):
                raise utils.ValidationError(
                    'Adjacent whitespace in tags should be collapsed, '
                    'received \'%s\'' % tag)

        if len(set(self.tags)) < len(self.tags):
            raise utils.ValidationError(
                'Expected tags to be unique, but found duplicates')

        if not isinstance(self.status, python_utils.BASESTRING):
            raise utils.ValidationError(
                'Expected status to be string, received %s' % self.status)

        if not isinstance(self.community_owned, bool):
            raise utils.ValidationError(
                'Expected community_owned to be bool, received %s' % (
                    self.community_owned))

        if not isinstance(self.owner_ids, list):
            raise utils.ValidationError(
                'Expected owner_ids to be list, received %s' % self.owner_ids)
        for owner_id in self.owner_ids:
            if not isinstance(owner_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in owner_ids to '
                    'be string, received %s' % owner_id)

        if not isinstance(self.editor_ids, list):
            raise utils.ValidationError(
                'Expected editor_ids to be list, received %s' % self.editor_ids)
        for editor_id in self.editor_ids:
            if not isinstance(editor_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in editor_ids to '
                    'be string, received %s' % editor_id)

        if not isinstance(self.viewer_ids, list):
            raise utils.ValidationError(
                'Expected viewer_ids to be list, received %s' % self.viewer_ids)
        for viewer_id in self.viewer_ids:
            if not isinstance(viewer_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in viewer_ids to '
                    'be string, received %s' % viewer_id)

        if not isinstance(self.contributor_ids, list):
            raise utils.ValidationError(
                'Expected contributor_ids to be list, received %s' % (
                    self.contributor_ids))
        for contributor_id in self.contributor_ids:
            if not isinstance(contributor_id, python_utils.BASESTRING):
                raise utils.ValidationError(
                    'Expected each id in contributor_ids to '
                    'be string, received %s' % contributor_id)

        if not isinstance(self.contributors_summary, dict):
            raise utils.ValidationError(
                'Expected contributors_summary to be dict, received %s' % (
                    self.contributors_summary))
Esempio n. 12
0
    def validate(self, strict=True):
        """Validates all properties of this collection and its constituents.

        Raises:
            ValidationError: One or more attributes of the Collection are not
            valid.
        """

        # NOTE TO DEVELOPERS: Please ensure that this validation logic is the
        # same as that in the frontend CollectionValidatorService.

        if not isinstance(self.title, basestring):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(self.title,
                                 'the collection title',
                                 allow_empty=True)

        if not isinstance(self.category, basestring):
            raise utils.ValidationError(
                'Expected category to be a string, received %s' %
                self.category)
        utils.require_valid_name(self.category,
                                 'the collection category',
                                 allow_empty=True)

        if not isinstance(self.objective, basestring):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not self.language_code:
            raise utils.ValidationError(
                'A language must be specified (in the \'Settings\' tab).')

        if not any([
                self.language_code == lc['code']
                for lc in feconf.ALL_LANGUAGE_CODES
        ]):
            raise utils.ValidationError('Invalid language code: %s' %
                                        self.language_code)

        if not isinstance(self.tags, list):
            raise utils.ValidationError(
                'Expected tags to be a list, received %s' % self.tags)

        if len(set(self.tags)) < len(self.tags):
            raise utils.ValidationError(
                'Expected tags to be unique, but found duplicates')

        for tag in self.tags:
            if not isinstance(tag, basestring):
                raise utils.ValidationError(
                    'Expected each tag to be a string, received \'%s\'' % tag)

            if not tag:
                raise utils.ValidationError('Tags should be non-empty.')

            if not re.match(feconf.TAG_REGEX, tag):
                raise utils.ValidationError(
                    'Tags should only contain lowercase letters and spaces, '
                    'received \'%s\'' % tag)

            if (tag[0] not in string.ascii_lowercase
                    or tag[-1] not in string.ascii_lowercase):
                raise utils.ValidationError(
                    'Tags should not start or end with whitespace, received '
                    ' \'%s\'' % tag)

            if re.search(r'\s\s+', tag):
                raise utils.ValidationError(
                    'Adjacent whitespace in tags should be collapsed, '
                    'received \'%s\'' % tag)

        if not isinstance(self.schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.schema_version)

        if self.schema_version != feconf.CURRENT_COLLECTION_SCHEMA_VERSION:
            raise utils.ValidationError(
                'Expected schema version to be %s, received %s' %
                (feconf.CURRENT_COLLECTION_SCHEMA_VERSION,
                 self.schema_version))

        if not isinstance(self.nodes, list):
            raise utils.ValidationError(
                'Expected nodes to be a list, received %s' % self.nodes)

        all_exp_ids = self.exploration_ids
        if len(set(all_exp_ids)) != len(all_exp_ids):
            raise utils.ValidationError(
                'There are explorations referenced in the collection more '
                'than once.')

        # Validate all collection nodes.
        for node in self.nodes:
            node.validate()

        if strict:
            if not self.title:
                raise utils.ValidationError(
                    'A title must be specified for the collection.')

            if not self.objective:
                raise utils.ValidationError(
                    'An objective must be specified for the collection.')

            if not self.category:
                raise utils.ValidationError(
                    'A category must be specified for the collection.')

            if not self.nodes:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration in the '
                    'collection.')

            # Ensure the collection may be started.
            if not self.init_exploration_ids:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration with no '
                    'prerequisite skills.')

            # Ensure the collection can be completed. This is done in two
            # steps: first, no exploration may grant a skill that it
            # simultaneously lists as a prerequisite. Second, every exploration
            # in the collection must be reachable when starting from the
            # explorations with no prerequisite skills and playing through all
            # subsequent explorations provided by get_next_exploration_ids.
            completed_exp_ids = set(self.init_exploration_ids)
            next_exp_ids = self.get_next_exploration_ids(
                list(completed_exp_ids))
            while next_exp_ids:
                completed_exp_ids.update(set(next_exp_ids))
                next_exp_ids = self.get_next_exploration_ids(
                    list(completed_exp_ids))

            if len(completed_exp_ids) != len(self.nodes):
                unreachable_ids = set(all_exp_ids) - completed_exp_ids
                raise utils.ValidationError(
                    'Some explorations are unreachable from the initial '
                    'explorations: %s' % unreachable_ids)
Esempio n. 13
0
    def validate(self, strict=True):
        """Validates all properties of this collection and its constituents."""

        # NOTE TO DEVELOPERS: Please ensure that this validation logic is the
        # same as that in the frontend CollectionValidatorService.

        if not isinstance(self.title, basestring):
            raise utils.ValidationError(
                'Expected title to be a string, received %s' % self.title)
        utils.require_valid_name(
            self.title, 'the collection title', allow_empty=True)

        if not isinstance(self.category, basestring):
            raise utils.ValidationError(
                'Expected category to be a string, received %s'
                % self.category)
        utils.require_valid_name(
            self.category, 'the collection category', allow_empty=True)

        if not isinstance(self.objective, basestring):
            raise utils.ValidationError(
                'Expected objective to be a string, received %s' %
                self.objective)

        if not isinstance(self.language_code, basestring):
            raise utils.ValidationError(
                'Expected language code to be a string, received %s' %
                self.language_code)

        if not self.language_code:
            raise utils.ValidationError(
                'A language must be specified (in the \'Settings\' tab).')

        if not any([self.language_code == lc['code']
                    for lc in feconf.ALL_LANGUAGE_CODES]):
            raise utils.ValidationError(
                'Invalid language code: %s' % self.language_code)

        if not isinstance(self.tags, list):
            raise utils.ValidationError(
                'Expected tags to be a list, received %s' % self.tags)

        if len(set(self.tags)) < len(self.tags):
            raise utils.ValidationError(
                'Expected tags to be unique, but found duplicates')

        for tag in self.tags:
            if not isinstance(tag, basestring):
                raise utils.ValidationError(
                    'Expected each tag to be a string, received \'%s\'' % tag)

            if not tag:
                raise utils.ValidationError('Tags should be non-empty.')

            if not re.match(feconf.TAG_REGEX, tag):
                raise utils.ValidationError(
                    'Tags should only contain lowercase letters and spaces, '
                    'received \'%s\'' % tag)

            if (tag[0] not in string.ascii_lowercase or
                    tag[-1] not in string.ascii_lowercase):
                raise utils.ValidationError(
                    'Tags should not start or end with whitespace, received '
                    ' \'%s\'' % tag)

            if re.search(r'\s\s+', tag):
                raise utils.ValidationError(
                    'Adjacent whitespace in tags should be collapsed, '
                    'received \'%s\'' % tag)

        if not isinstance(self.schema_version, int):
            raise utils.ValidationError(
                'Expected schema version to be an integer, received %s' %
                self.schema_version)

        if self.schema_version != feconf.CURRENT_COLLECTION_SCHEMA_VERSION:
            raise utils.ValidationError(
                'Expected schema version to be %s, received %s' % (
                    feconf.CURRENT_COLLECTION_SCHEMA_VERSION,
                    self.schema_version))

        if not isinstance(self.nodes, list):
            raise utils.ValidationError(
                'Expected nodes to be a list, received %s' % self.nodes)

        all_exp_ids = self.exploration_ids
        if len(set(all_exp_ids)) != len(all_exp_ids):
            raise utils.ValidationError(
                'There are explorations referenced in the collection more '
                'than once.')

        # Validate all collection nodes.
        for node in self.nodes:
            node.validate()

        if strict:
            if not self.title:
                raise utils.ValidationError(
                    'A title must be specified for the collection.')

            if not self.objective:
                raise utils.ValidationError(
                    'An objective must be specified for the collection.')

            if not self.category:
                raise utils.ValidationError(
                    'A category must be specified for the collection.')

            if not self.nodes:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration in the '
                    'collection.')

            # Ensure the collection may be started.
            if not self.init_exploration_ids:
                raise utils.ValidationError(
                    'Expected to have at least 1 exploration with no '
                    'prerequisite skills.')

            # Ensure the collection can be completed. This is done in two
            # steps: first, no exploration may grant a skill that it
            # simultaneously lists as a prerequisite. Second, every exploration
            # in the collection must be reachable when starting from the
            # explorations with no prerequisite skills and playing through all
            # subsequent explorations provided by get_next_exploration_ids.
            completed_exp_ids = set(self.init_exploration_ids)
            next_exp_ids = self.get_next_exploration_ids(
                list(completed_exp_ids))
            while next_exp_ids:
                completed_exp_ids.update(set(next_exp_ids))
                next_exp_ids = self.get_next_exploration_ids(
                    list(completed_exp_ids))

            if len(completed_exp_ids) != len(self.nodes):
                unreachable_ids = set(all_exp_ids) - completed_exp_ids
                raise utils.ValidationError(
                    'Some explorations are unreachable from the initial '
                    'explorations: %s' % unreachable_ids)
Esempio n. 14
0
    def validate(self):
        """Validates the training job before it is saved to storage."""

        algorithm_ids = []
        if not isinstance(self.job_id, basestring):
            raise utils.ValidationError(
                'Expected id to be a string, received %s' % self.job_id)

        if not isinstance(self.exp_id, basestring):
            raise utils.ValidationError(
                'Expected exp_id to be a string, received %s' % self.exp_id)

        if not isinstance(self.exp_version_when_created, int):
            raise utils.ValidationError(
                'Expected exp_version_when_created to be an int, received %s' %
                self.exp_version_when_created)

        if not isinstance(self.state_name, basestring):
            raise utils.ValidationError(
                'Expected state to be a string, received %s' % self.state_name)
        utils.require_valid_name(self.state_name, 'the state name')

        if self.status not in feconf.ALLOWED_TRAINING_JOB_STATUSES:
            raise utils.ValidationError(
                'Expected status to be in %s, received %s' %
                feconf.ALLOWED_TRAINING_JOB_STATUSES,
                self.exp_version_when_created)

        if not isinstance(self.algorithm_id, basestring):
            raise utils.ValidationError(
                'Expected algorithm_id to be a string, received %s' %
                self.algorithm_id)

        algorithm_ids = [
            classifier_details['algorithm_id'] for classifier_details in
            feconf.INTERACTION_CLASSIFIER_MAPPING.values()
        ]
        if self.algorithm_id not in algorithm_ids:
            raise utils.ValidationError('Invalid algorithm id: %s' %
                                        self.algorithm_id)

        if not isinstance(self.training_data, list):
            raise utils.ValidationError(
                'Expected training_data to be a list, received %s' %
                (self.training_data))

        for grouped_answers in self.training_data:
            if 'answer_group_index' not in grouped_answers:
                raise utils.ValidationError(
                    'Expected answer_group_index to be a key in training_data',
                    'list item')
            if 'answers' not in grouped_answers:
                raise utils.ValidationError(
                    'Expected answers to be a key in training_data list item')
            if not isinstance(grouped_answers['answer_group_index'], int):
                raise utils.ValidationError(
                    'Expected answer_group_index to be an int, received %s' %
                    grouped_answers['answer_group_index'])
            if not isinstance(grouped_answers['answers'], list):
                raise utils.ValidationError(
                    'Expected answers to be a list, received %s' %
                    grouped_answers['answers'])