def translate(self, text, source_language_code, target_language_code): """Returns the saved expected response for a given input. If no response exists for the given input, returns a default response. Args: text: str. The text to be translated. source_language_code: str. An allowlisted language code. target_language_code: str. An allowlisted language code. Raises: ValueError. Invalid source language code. ValueError. Invalid target language code. Returns: str. The translated text. """ if not utils.is_valid_language_code(source_language_code): raise ValueError('Invalid source language code: %s' % source_language_code) if not utils.is_valid_language_code(target_language_code): raise ValueError('Invalid target language code: %s' % target_language_code) key = (source_language_code, target_language_code, text) return self.expected_responses.get(key, self.DEFAULT_RESPONSE)
def validate(self): """Validates properties of the MachineTranslation. Raises: ValidationError. One or more attributes of the MachineTranslation are invalid. """ if not isinstance(self.source_language_code, python_utils.BASESTRING): raise utils.ValidationError( 'Expected source_language_code to be a string, received %s' % self.source_language_code ) # TODO(#12341): Tidy up this logic once we have a canonical list of # language codes. if not utils.is_supported_audio_language_code( self.source_language_code ) and not utils.is_valid_language_code( self.source_language_code ): raise utils.ValidationError( 'Invalid source language code: %s' % self.source_language_code) if not isinstance(self.target_language_code, python_utils.BASESTRING): raise utils.ValidationError( 'Expected target_language_code to be a string, received %s' % self.target_language_code ) # TODO(#12341): Tidy up this logic once we have a canonical list of # language codes. if not utils.is_supported_audio_language_code( self.target_language_code ) and not utils.is_valid_language_code( self.target_language_code ): raise utils.ValidationError( 'Invalid target language code: %s' % self.target_language_code) if self.source_language_code == self.target_language_code: raise utils.ValidationError( ( 'Expected source_language_code to be different from ' 'target_language_code: "%s" = "%s"') % ( self.source_language_code, self.target_language_code)) if not isinstance(self.source_text, python_utils.BASESTRING): raise utils.ValidationError( 'Expected source_text to be a string, received %s' % self.source_text ) if not isinstance(self.translated_text, python_utils.BASESTRING): raise utils.ValidationError( 'Expected translated_text to be a string, received %s' % self.translated_text )
def validate(self): """Validates various properties of the story summary object. Raises: ValidationError: One or more attributes of story summary are invalid. """ if not isinstance(self.title, basestring): raise utils.ValidationError( 'Expected title to be a string, received %s' % self.title) if self.title == '': raise utils.ValidationError('Title field should not be empty') if not isinstance(self.description, basestring): raise utils.ValidationError( 'Expected description to be a string, received %s' % self.description) if not isinstance(self.node_count, int): raise utils.ValidationError( 'Expected node_count to be a int, received \'%s\'' % ( self.node_count)) if not isinstance(self.language_code, 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)
def partial_validate(self): """Validates the Question domain object, but doesn't require the object to contain an ID and a version. To be used to validate the question before it is finalized. """ if not isinstance(self.language_code, basestring): raise utils.ValidationError( 'Expected language_code to be a string, received %s' % self.language_code) if not isinstance(self.question_state_schema_version, int): raise utils.ValidationError( 'Expected schema version to be an integer, received %s' % self.question_state_schema_version) if not isinstance(self.question_state_data, state_domain.State): raise utils.ValidationError( 'Expected question state data to be a State object, ' 'received %s' % self.question_state_data) if not utils.is_valid_language_code(self.language_code): raise utils.ValidationError('Invalid language code: %s' % self.language_code) INTERACTION_SPECS = interaction_registry.Registry.get_all_specs() at_least_one_correct_answer = False dest_is_specified = False interaction = self.question_state_data.interaction for answer_group in interaction.answer_groups: if answer_group.outcome.labelled_as_correct: at_least_one_correct_answer = True if answer_group.outcome.dest is not None: dest_is_specified = True if interaction.default_outcome.labelled_as_correct: at_least_one_correct_answer = True if interaction.default_outcome.dest is not None: dest_is_specified = True if not at_least_one_correct_answer: raise utils.ValidationError( 'Expected at least one answer group to have a correct ' + 'answer.') if dest_is_specified: raise utils.ValidationError( 'Expected all answer groups to have destination as None.') if not interaction.hints: raise utils.ValidationError( 'Expected the question to have at least one hint') if ((interaction.solution is None) and (INTERACTION_SPECS[interaction.id]['can_have_solution'])): raise utils.ValidationError( 'Expected the question to have a solution') self.question_state_data.validate({}, False)
def is_valid_audio_language_code(obj: str) -> bool: """Checks if the given obj (a string) represents a valid language code. Args: obj: str. The language code to verify. Returns: bool. Whether the given object is a valid audio language code. """ return utils.is_valid_language_code(obj)
def validate(self): """Validates various properties of the story object. Raises: ValidationError: One or more attributes of story are invalid. """ self.require_valid_title(self.title) if not isinstance(self.description, python_utils.BASESTRING): raise utils.ValidationError( 'Expected description to be a string, received %s' % self.description) if not isinstance(self.notes, python_utils.BASESTRING): raise utils.ValidationError( 'Expected notes to be a string, received %s' % self.notes) if not isinstance(self.story_contents_schema_version, int): raise utils.ValidationError( 'Expected story contents schema version to be an integer, ' 'received %s' % self.story_contents_schema_version) if (self.story_contents_schema_version != feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION): raise utils.ValidationError( 'Expected story contents schema version to be %s, ' 'received %s' % ( feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION, self.story_contents_schema_version)) 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.corresponding_topic_id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected corresponding_topic_id should be a string, received: ' '%s' % self.corresponding_topic_id) self.story_contents.validate()
def validate(self): """Validates various properties of the Skill Summary object. Raises: ValidationError: One or more attributes of skill summary are invalid. """ if not isinstance(self.description, python_utils.BASESTRING): raise utils.ValidationError('Description should be a string.') if self.description == '': raise utils.ValidationError( 'Description field should not be empty') 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.misconception_count, int): raise utils.ValidationError( 'Expected misconception_count to be an int, ' 'received \'%s\'' % self.misconception_count) if self.misconception_count < 0: raise utils.ValidationError( 'Expected misconception_count to be non-negative, ' 'received \'%s\'' % self.misconception_count) if not isinstance(self.worked_examples_count, int): raise utils.ValidationError( 'Expected worked_examples_count to be an int, ' 'received \'%s\'' % self.worked_examples_count) if self.worked_examples_count < 0: raise utils.ValidationError( 'Expected worked_examples_count to be non-negative, ' 'received \'%s\'' % self.worked_examples_count)
def validate(self): """Validates various properties of the story object. Raises: ValidationError: One or more attributes of story are invalid. """ self.require_valid_title(self.title) if not isinstance(self.description, basestring): raise utils.ValidationError( 'Expected description to be a string, received %s' % self.description) if not isinstance(self.notes, basestring): raise utils.ValidationError( 'Expected notes to be a string, received %s' % self.notes) 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_STORY_CONTENTS_SCHEMA_VERSION: raise utils.ValidationError( 'Expected schema version to be %s, received %s' % (feconf.CURRENT_STORY_CONTENTS_SCHEMA_VERSION, self.schema_version)) if not isinstance(self.language_code, 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) self.story_contents.validate()
def partial_validate(self): """Validates the Question domain object, but doesn't require the object to contain an ID and a version. To be used to validate the question before it is finalized. """ 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 self.linked_skill_ids: raise utils.ValidationError( 'linked_skill_ids is either null or an empty list') if not (isinstance(self.linked_skill_ids, list) and (all( isinstance(elem, python_utils.BASESTRING) for elem in (self.linked_skill_ids)))): raise utils.ValidationError( 'Expected linked_skill_ids to be a list of strings, ' 'received %s' % self.linked_skill_ids) if len(set(self.linked_skill_ids)) != len(self.linked_skill_ids): raise utils.ValidationError( 'linked_skill_ids has duplicate skill ids') if not isinstance(self.question_state_data_schema_version, int): raise utils.ValidationError( 'Expected schema version to be an integer, received %s' % self.question_state_data_schema_version) if not isinstance(self.question_state_data, state_domain.State): raise utils.ValidationError( 'Expected question state data to be a State object, ' 'received %s' % self.question_state_data) if not utils.is_valid_language_code(self.language_code): raise utils.ValidationError('Invalid language code: %s' % self.language_code) interaction_specs = interaction_registry.Registry.get_all_specs() at_least_one_correct_answer = False dest_is_specified = False interaction = self.question_state_data.interaction for answer_group in interaction.answer_groups: if answer_group.outcome.labelled_as_correct: at_least_one_correct_answer = True if answer_group.outcome.dest is not None: dest_is_specified = True if interaction.default_outcome.labelled_as_correct: at_least_one_correct_answer = True if interaction.default_outcome.dest is not None: dest_is_specified = True if not at_least_one_correct_answer: raise utils.ValidationError( 'Expected at least one answer group to have a correct ' + 'answer.') if dest_is_specified: raise utils.ValidationError( 'Expected all answer groups to have destination as None.') if not interaction.hints: raise utils.ValidationError( 'Expected the question to have at least one hint') if ((interaction.solution is None) and (interaction_specs[interaction.id]['can_have_solution'])): raise utils.ValidationError( 'Expected the question to have a solution') self.question_state_data.validate({}, False)
def validate(self): """Validates all properties of this topic and its constituents. Raises: ValidationError: One or more attributes of the Topic are not valid. """ self.require_valid_name(self.name) if not isinstance(self.description, python_utils.BASESTRING): raise utils.ValidationError( 'Expected description to be a string, received %s' % self.description) if not isinstance(self.subtopics, list): raise utils.ValidationError( 'Expected subtopics to be a list, received %s' % self.subtopics) if not isinstance(self.next_subtopic_id, int): raise utils.ValidationError( 'Expected next_subtopic_id to be an int, received %s' % self.next_subtopic_id) if not isinstance(self.subtopic_schema_version, int): raise utils.ValidationError( 'Expected subtopic schema version to be an integer, received %s' % self.subtopic_schema_version) if not isinstance(self.story_reference_schema_version, int): raise utils.ValidationError( 'Expected story reference schema version to be an integer, ' 'received %s' % self.story_reference_schema_version) if (self.subtopic_schema_version != feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION): raise utils.ValidationError( 'Expected subtopic schema version to be %s, received %s' % (feconf.CURRENT_SUBTOPIC_SCHEMA_VERSION, self.subtopic_schema_version)) for subtopic in self.subtopics: if not isinstance(subtopic, Subtopic): raise utils.ValidationError( 'Expected each subtopic to be a Subtopic object, ' 'received %s' % subtopic) subtopic.validate() if subtopic.id >= self.next_subtopic_id: raise utils.ValidationError( 'The id for subtopic %s is greater than or equal to ' 'next_subtopic_id %s' % (subtopic.id, self.next_subtopic_id)) 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.canonical_story_references, list): raise utils.ValidationError( 'Expected canonical story references to be a list, received %s' % self.canonical_story_references) canonical_story_ids = self.get_canonical_story_ids() if len(canonical_story_ids) > len(set(canonical_story_ids)): raise utils.ValidationError( 'Expected all canonical story ids to be distinct.') if not isinstance(self.additional_story_references, list): raise utils.ValidationError( 'Expected additional story references to be a list, received %s' % self.additional_story_references) additional_story_ids = self.get_additional_story_ids() if len(additional_story_ids) > len(set(additional_story_ids)): raise utils.ValidationError( 'Expected all additional story ids to be distinct.') for story_id in additional_story_ids: if story_id in canonical_story_ids: raise utils.ValidationError( 'Expected additional story ids list and canonical story ' 'ids list to be mutually exclusive. The story_id %s is ' 'present in both lists' % story_id) all_story_references = self.get_all_story_references() for reference in all_story_references: reference.validate() if not isinstance(self.uncategorized_skill_ids, list): raise utils.ValidationError( 'Expected uncategorized skill ids to be a list, received %s' % self.uncategorized_skill_ids)
def validate(self): """Validates all properties of this topic summary. Raises: ValidationError: One or more attributes of the Topic summary are not valid. """ if not isinstance(self.name, python_utils.BASESTRING): raise utils.ValidationError('Name should be a string.') if self.name == '': raise utils.ValidationError('Name field should not be empty') if not isinstance(self.canonical_name, python_utils.BASESTRING): raise utils.ValidationError('Canonical name should be a string.') if self.canonical_name == '': raise utils.ValidationError( 'Canonical name field should not be empty') 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.canonical_story_count, int): raise utils.ValidationError( 'Expected canonical story count to be an integer, ' 'received \'%s\'' % self.canonical_story_count) if self.canonical_story_count < 0: raise utils.ValidationError( 'Expected canonical_story_count to be non-negative, ' 'received \'%s\'' % self.canonical_story_count) if not isinstance(self.additional_story_count, int): raise utils.ValidationError( 'Expected additional story count to be an integer, ' 'received \'%s\'' % self.additional_story_count) if self.additional_story_count < 0: raise utils.ValidationError( 'Expected additional_story_count to be non-negative, ' 'received \'%s\'' % self.additional_story_count) if not isinstance(self.uncategorized_skill_count, int): raise utils.ValidationError( 'Expected uncategorized skill count to be an integer, ' 'received \'%s\'' % self.uncategorized_skill_count) if self.uncategorized_skill_count < 0: raise utils.ValidationError( 'Expected uncategorized_skill_count to be non-negative, ' 'received \'%s\'' % self.uncategorized_skill_count) if not isinstance(self.total_skill_count, int): raise utils.ValidationError( 'Expected total skill count to be an integer, received \'%s\'' % self.total_skill_count) if self.total_skill_count < 0: raise utils.ValidationError( 'Expected total_skill_count to be non-negative, ' 'received \'%s\'' % self.total_skill_count) if self.total_skill_count < self.uncategorized_skill_count: raise utils.ValidationError( 'Expected total_skill_count to be greater than or equal to ' 'uncategorized_skill_count %s, received \'%s\'' % (self.uncategorized_skill_count, self.total_skill_count)) if not isinstance(self.subtopic_count, int): raise utils.ValidationError( 'Expected subtopic count to be an integer, received \'%s\'' % self.subtopic_count) if self.subtopic_count < 0: raise utils.ValidationError( 'Expected subtopic_count to be non-negative, ' 'received \'%s\'' % self.subtopic_count)
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))
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.')
def test_is_valid_language_code(self): self.assertTrue(utils.is_valid_language_code('en')) self.assertFalse(utils.is_valid_language_code('unknown'))
def validate(self): """Validates various properties of the Skill object. Raises: ValidationError: One or more attributes of skill are invalid. """ self.require_valid_description(self.description) Misconception.require_valid_misconception_id(self.next_misconception_id) if not isinstance(self.misconceptions_schema_version, int): raise utils.ValidationError( 'Expected misconceptions schema version to be an integer, ' 'received %s' % self.misconceptions_schema_version) if ( self.misconceptions_schema_version != feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION): raise utils.ValidationError( 'Expected misconceptions schema version to be %s, received %s' % ( feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION, self.misconceptions_schema_version) ) if not isinstance(self.skill_contents_schema_version, int): raise utils.ValidationError( 'Expected skill contents schema version to be an integer, ' 'received %s' % self.skill_contents_schema_version) if ( self.skill_contents_schema_version != feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION): raise utils.ValidationError( 'Expected skill contents schema version to be %s, received %s' % ( feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION, self.skill_contents_schema_version) ) if not isinstance(self.language_code, 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.skill_contents, SkillContents): raise utils.ValidationError( 'Expected skill_contents to be a SkillContents object, ' 'received %s' % self.skill_contents) self.skill_contents.validate() if not isinstance(self.misconceptions, list): raise utils.ValidationError( 'Expected misconceptions to be a list, ' 'received %s' % self.skill_contents) misconception_id_list = [] for misconception in self.misconceptions: if not isinstance(misconception, Misconception): raise utils.ValidationError( 'Expected each misconception to be a Misconception ' 'object, received %s' % misconception) if misconception.id in misconception_id_list: raise utils.ValidationError( 'Duplicate misconception ID found: %s' % misconception.id) misconception_id_list.append(misconception.id) if int(misconception.id) >= int(self.next_misconception_id): raise utils.ValidationError( 'The misconception with id %s is out of bounds.' % misconception.id) misconception.validate() if (self.all_questions_merged and self.superseding_skill_id is None): raise utils.ValidationError( 'Expected a value for superseding_skill_id when ' 'all_questions_merged is True.') if (self.superseding_skill_id is not None and self.all_questions_merged is None): raise utils.ValidationError( 'Expected a value for all_questions_merged when ' 'superseding_skill_id is set.')
def validate(self): """Validates various properties of the Skill object. Raises: ValidationError: One or more attributes of skill are invalid. """ self.require_valid_description(self.description) Misconception.require_valid_misconception_id( self.next_misconception_id) if not isinstance(self.misconceptions_schema_version, int): raise utils.ValidationError( 'Expected misconceptions schema version to be an integer, ' 'received %s' % self.misconceptions_schema_version) if (self.misconceptions_schema_version != feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION): raise utils.ValidationError( 'Expected misconceptions schema version to be %s, received %s' % (feconf.CURRENT_MISCONCEPTIONS_SCHEMA_VERSION, self.misconceptions_schema_version)) if not isinstance(self.rubric_schema_version, int): raise utils.ValidationError( 'Expected rubric schema version to be an integer, ' 'received %s' % self.rubric_schema_version) if (self.rubric_schema_version != feconf.CURRENT_RUBRIC_SCHEMA_VERSION): raise utils.ValidationError( 'Expected rubric schema version to be %s, received %s' % (feconf.CURRENT_RUBRIC_SCHEMA_VERSION, self.rubric_schema_version)) if not isinstance(self.skill_contents_schema_version, int): raise utils.ValidationError( 'Expected skill contents schema version to be an integer, ' 'received %s' % self.skill_contents_schema_version) if (self.skill_contents_schema_version != feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION): raise utils.ValidationError( 'Expected skill contents schema version to be %s, received %s' % (feconf.CURRENT_SKILL_CONTENTS_SCHEMA_VERSION, self.skill_contents_schema_version)) 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.skill_contents, SkillContents): raise utils.ValidationError( 'Expected skill_contents to be a SkillContents object, ' 'received %s' % self.skill_contents) self.skill_contents.validate() if not isinstance(self.rubrics, list): raise utils.ValidationError('Expected rubrics to be a list, ' 'received %s' % self.skill_contents) difficulties_list = [] for rubric in self.rubrics: if not isinstance(rubric, Rubric): raise utils.ValidationError( 'Expected each rubric to be a Rubric ' 'object, received %s' % rubric) if rubric.difficulty in difficulties_list: raise utils.ValidationError('Duplicate rubric found for: %s' % rubric.difficulty) difficulties_list.append(rubric.difficulty) rubric.validate() if len(difficulties_list) != 3: raise utils.ValidationError( 'All 3 difficulties should be addressed in rubrics') if difficulties_list != constants.SKILL_DIFFICULTIES: raise utils.ValidationError( 'The difficulties should be ordered as follows [%s, %s, %s]' % (constants.SKILL_DIFFICULTIES[0], constants.SKILL_DIFFICULTIES[1], constants.SKILL_DIFFICULTIES[2])) if not isinstance(self.misconceptions, list): raise utils.ValidationError( 'Expected misconceptions to be a list, ' 'received %s' % self.misconceptions) if not isinstance(self.prerequisite_skill_ids, list): raise utils.ValidationError( 'Expected prerequisite_skill_ids to be a list, ' 'received %s' % self.prerequisite_skill_ids) for skill_id in self.prerequisite_skill_ids: if not isinstance(skill_id, python_utils.BASESTRING): raise utils.ValidationError( 'Expected each skill ID to be a string, ' 'received %s' % skill_id) misconception_id_list = [] for misconception in self.misconceptions: if not isinstance(misconception, Misconception): raise utils.ValidationError( 'Expected each misconception to be a Misconception ' 'object, received %s' % misconception) if misconception.id in misconception_id_list: raise utils.ValidationError( 'Duplicate misconception ID found: %s' % misconception.id) misconception_id_list.append(misconception.id) if int(misconception.id) >= int(self.next_misconception_id): raise utils.ValidationError( 'The misconception with id %s is out of bounds.' % misconception.id) misconception.validate() if (self.all_questions_merged and self.superseding_skill_id is None): raise utils.ValidationError( 'Expected a value for superseding_skill_id when ' 'all_questions_merged is True.') if (self.superseding_skill_id is not None and self.all_questions_merged is None): raise utils.ValidationError( 'Expected a value for all_questions_merged when ' 'superseding_skill_id is set.')
def get(self): """Handles GET requests. Responds with a mapping from content id to translation of form: dict('translated_texts', dict(str, str|None)) If no translation is found for a given content id, that id is mapped to None. Params: exp_id: str. The ID of the exploration being translated. state_name: str. The name of the exploration state being translated. content_ids: str[]. The content IDs of the texts to be translated. target_language_code: str. The language code of the target translation language. Data Response: dict('translated_texts': dict(str, str|None)) A dictionary containing the translated texts stored as a mapping from content ID to the translated text. If an error occured during retrieval of some content translations, but not others, failed translations are mapped to None. Raises: 400 (Bad Request): InvalidInputException. At least one input is missing or improperly formatted. 404 (Not Found): PageNotFoundException. At least one identifier does not correspond to an entry in the datastore. """ exp_id = self.request.get('exp_id') if not exp_id: raise self.InvalidInputException('Missing exp_id') state_name = self.request.get('state_name') if not state_name: raise self.InvalidInputException('Missing state_name') content_ids_string = self.request.get('content_ids') content_ids = [] try: content_ids = json.loads(content_ids_string) except: raise self.InvalidInputException( 'Improperly formatted content_ids: %s' % content_ids_string) target_language_code = self.request.get('target_language_code') if not target_language_code: raise self.InvalidInputException('Missing target_language_code') # TODO(#12341): Tidy up this logic once we have a canonical list of # language codes. if not utils.is_supported_audio_language_code( target_language_code) and not utils.is_valid_language_code( target_language_code): raise self.InvalidInputException( 'Invalid target_language_code: %s' % target_language_code) exp = exp_fetchers.get_exploration_by_id(exp_id, strict=False) if exp is None: raise self.PageNotFoundException() state_names_to_content_id_mapping = exp.get_translatable_text( target_language_code) if state_name not in state_names_to_content_id_mapping: raise self.PageNotFoundException() content_id_to_text_mapping = ( state_names_to_content_id_mapping[state_name]) translated_texts = {} for content_id in content_ids: if content_id not in content_id_to_text_mapping: translated_texts[content_id] = None continue source_text = content_id_to_text_mapping[content_id] translated_texts[content_id] = ( translation_services.get_and_cache_machine_translation( exp.language_code, target_language_code, source_text)) self.values = {'translated_texts': translated_texts} self.render_json(self.values)