def validate(self) -> None: """Validates the training job before it is saved to storage.""" algorithm_ids = [] 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 self.interaction_id not in feconf.INTERACTION_CLASSIFIER_MAPPING: raise utils.ValidationError('Invalid interaction id: %s' % self.interaction_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')
def test_require_valid_name(self) -> None: name = 'name' utils.require_valid_name(name, 'name_type') invalid_name = 0 with self.assertRaisesRegex(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]
def test_require_valid_name_with_incorrect_input(self) -> None: with self.assertRaisesRegex( # type: ignore[no-untyped-call] utils.ValidationError, 'The length of the exploration title should be between 1 and 50 ' 'characters; received '): # pylint: disable=line-too-long utils.require_valid_name('', 'the exploration title') with self.assertRaisesRegex( # type: ignore[no-untyped-call] utils.ValidationError, 'Names should not start or end with whitespace.'): utils.require_valid_name(' 123\n', 'the exploration title') with self.assertRaisesRegex( # type: ignore[no-untyped-call] utils.ValidationError, 'Adjacent whitespace in the exploration title should be collapsed.'): # pylint: disable=line-too-long utils.require_valid_name('1 23', 'the exploration title') with self.assertRaisesRegex( # type: ignore[no-untyped-call] utils.ValidationError, 'Invalid character : in the exploration title: 1\n:23'): utils.require_valid_name('1\n:23', 'the exploration title') with self.assertRaisesRegex( # type: ignore[no-untyped-call] utils.ValidationError, r'Invalid character \\n in the exploration title: 1\\n23'): utils.require_valid_name('1\\n23', 'the exploration title')
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']) if not isinstance(self.algorithm_version, int): raise utils.ValidationError( 'Expected algorithm_version to be an int, received %s' % self.algorithm_version)
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, str): 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, str): 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, str): raise utils.ValidationError( 'Expected objective to be a string, received %s' % self.objective) if not isinstance(self.language_code, str): 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) 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, str): 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 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.')
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, str): 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, str): 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, str): 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, str): 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, str): 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, str): 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, str): 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, str): 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, str): 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, str): 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))
def test_get_require_valid_name_with_empty_string(self) -> None: utils.require_valid_name('', 'the exploration title', allow_empty=True)