def translate_location(self, location, published=True, add_entry_if_missing=True, passed_block_id=None): """ Translate the given module location to a Locator. The rationale for auto adding entries was that there should be a reasonable default translation if the code just trips into this w/o creating translations. Will raise ItemNotFoundError if there's no mapping and add_entry_if_missing is False. :param location: a Location pointing to a module :param published: a boolean to indicate whether the caller wants the draft or published branch. :param add_entry_if_missing: a boolean as to whether to raise ItemNotFoundError or to create an entry if the course or block is not found in the map. :param passed_block_id: what block_id to assign and save if none is found (only if add_entry_if_missing) NOTE: unlike old mongo, draft branches contain the whole course; so, it applies to all category of locations including course. """ course_son = self._interpret_location_course_id(location.course_key) cached_value = self._get_locator_from_cache(location, published) if cached_value: return cached_value entry = self.location_map.find_one(course_son) if entry is None: if add_entry_if_missing: # create a new map self.create_map_entry(location.course_key) entry = self.location_map.find_one(course_son) else: raise ItemNotFoundError(location) else: entry = self._migrate_if_necessary([entry])[0] block_id = entry['block_map'].get(self.encode_key_for_mongo(location.name)) category = location.category if block_id is None: if add_entry_if_missing: block_id = self._add_to_block_map( location, course_son, entry['block_map'], passed_block_id ) else: raise ItemNotFoundError(location) else: # jump_to_id uses a None category. if category is None: if len(block_id) == 1: # unique match (most common case) category = block_id.keys()[0] block_id = block_id.values()[0] else: raise InvalidLocationError() elif category in block_id: block_id = block_id[category] elif add_entry_if_missing: block_id = self._add_to_block_map(location, course_son, entry['block_map']) else: raise ItemNotFoundError(location) prod_course_locator = CourseLocator( org=entry['org'], offering=entry['offering'], branch=entry['prod_branch'] ) published_usage = BlockUsageLocator( prod_course_locator, block_type=category, block_id=block_id ) draft_usage = BlockUsageLocator( prod_course_locator.for_branch(entry['draft_branch']), block_type=category, block_id=block_id ) if published: result = published_usage else: result = draft_usage self._cache_location_map_entry(location, published_usage, draft_usage) return result
def test_translate_locator(self): """ tests translate_locator_to_location(BlockUsageLocator) """ # lookup for non-existent course org = "foo_org" course = "bar_course" run = "baz_run" new_style_org = "{}.geek_dept".format(org) new_style_offering = "{}.{}".format(course, run) prob_course_key = CourseLocator( org=new_style_org, offering=new_style_offering, branch=ModuleStoreEnum.BranchName.published ) prob_locator = BlockUsageLocator(prob_course_key, block_type="problem", block_id="problem2") prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertIsNone(prob_location, "found entry in empty map table") loc_mapper().create_map_entry( SlashSeparatedCourseKey(org, course, run), new_style_org, new_style_offering, block_map={ "abc123": {"problem": "problem2"}, "48f23a10395384929234": {"chapter": "chapter48f"}, "baz_run": {"course": "root"}, }, ) # only one course matches prob_location = loc_mapper().translate_locator_to_location(prob_locator) # default branch self.assertEqual(prob_location, Location(org, course, run, "problem", "abc123", MongoRevisionKey.published)) # test get_course keyword prob_location = loc_mapper().translate_locator_to_location(prob_locator, get_course=True) self.assertEqual(prob_location, SlashSeparatedCourseKey(org, course, run)) # explicit branch prob_locator = prob_locator.for_branch(ModuleStoreEnum.BranchName.draft) prob_location = loc_mapper().translate_locator_to_location(prob_locator) # Even though the problem was set as draft, we always return revision= MongoRevisionKey.published to work # with old mongo/draft modulestores. self.assertEqual(prob_location, Location(org, course, run, "problem", "abc123", MongoRevisionKey.published)) prob_locator = BlockUsageLocator( prob_course_key.for_branch("production"), block_type="problem", block_id="problem2" ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertEqual(prob_location, Location(org, course, run, "problem", "abc123", MongoRevisionKey.published)) # same for chapter except chapter cannot be draft in old system chap_locator = BlockUsageLocator( prob_course_key.for_branch("production"), block_type="chapter", block_id="chapter48f" ) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, "chapter", "48f23a10395384929234")) # explicit branch chap_locator = chap_locator.for_branch(ModuleStoreEnum.BranchName.draft) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, "chapter", "48f23a10395384929234")) chap_locator = BlockUsageLocator( prob_course_key.for_branch("production"), block_type="chapter", block_id="chapter48f" ) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, "chapter", "48f23a10395384929234")) # look for non-existent problem prob_locator2 = BlockUsageLocator( prob_course_key.for_branch(ModuleStoreEnum.BranchName.draft), block_type="problem", block_id="problem3" ) prob_location = loc_mapper().translate_locator_to_location(prob_locator2) self.assertIsNone(prob_location, "Found non-existent problem") # add a distractor course delta_run = "delta_run" new_style_offering = "{}.{}".format(course, delta_run) loc_mapper().create_map_entry( SlashSeparatedCourseKey(org, course, delta_run), new_style_org, new_style_offering, block_map={"abc123": {"problem": "problem3"}}, ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertEqual(prob_location, Location(org, course, run, "problem", "abc123", MongoRevisionKey.published))
def translate_location(self, location, published=True, add_entry_if_missing=True, passed_block_id=None): """ Translate the given module location to a Locator. The rationale for auto adding entries was that there should be a reasonable default translation if the code just trips into this w/o creating translations. Will raise ItemNotFoundError if there's no mapping and add_entry_if_missing is False. :param location: a Location pointing to a module :param published: a boolean to indicate whether the caller wants the draft or published branch. :param add_entry_if_missing: a boolean as to whether to raise ItemNotFoundError or to create an entry if the course or block is not found in the map. :param passed_block_id: what block_id to assign and save if none is found (only if add_entry_if_missing) NOTE: unlike old mongo, draft branches contain the whole course; so, it applies to all category of locations including course. """ course_son = self._interpret_location_course_id(location.course_key) cached_value = self._get_locator_from_cache(location, published) if cached_value: return cached_value entry = self.location_map.find_one(course_son) if entry is None: if add_entry_if_missing: # create a new map self.create_map_entry(location.course_key) entry = self.location_map.find_one(course_son) else: raise ItemNotFoundError(location) else: entry = self._migrate_if_necessary([entry])[0] block_id = entry['block_map'].get( self.encode_key_for_mongo(location.name)) category = location.category if block_id is None: if add_entry_if_missing: block_id = self._add_to_block_map(location, course_son, entry['block_map'], passed_block_id) else: raise ItemNotFoundError(location) else: # jump_to_id uses a None category. if category is None: if len(block_id) == 1: # unique match (most common case) category = block_id.keys()[0] block_id = block_id.values()[0] else: raise InvalidLocationError() elif category in block_id: block_id = block_id[category] elif add_entry_if_missing: block_id = self._add_to_block_map(location, course_son, entry['block_map']) else: raise ItemNotFoundError(location) prod_course_locator = CourseLocator(org=entry['org'], offering=entry['offering'], branch=entry['prod_branch']) published_usage = BlockUsageLocator(prod_course_locator, block_type=category, block_id=block_id) draft_usage = BlockUsageLocator(prod_course_locator.for_branch( entry['draft_branch']), block_type=category, block_id=block_id) if published: result = published_usage else: result = draft_usage self._cache_location_map_entry(location, published_usage, draft_usage) return result
def test_translate_locator(self): """ tests translate_locator_to_location(BlockUsageLocator) """ # lookup for non-existent course org = 'foo_org' course = 'bar_course' run = 'baz_run' new_style_org = '{}.geek_dept'.format(org) new_style_offering = '{}.{}'.format(course, run) prob_course_key = CourseLocator( org=new_style_org, offering=new_style_offering, branch=BRANCH_NAME_PUBLISHED, ) prob_locator = BlockUsageLocator( prob_course_key, block_type='problem', block_id='problem2', ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertIsNone(prob_location, 'found entry in empty map table') loc_mapper().create_map_entry( SlashSeparatedCourseKey(org, course, run), new_style_org, new_style_offering, block_map={ 'abc123': {'problem': 'problem2'}, '48f23a10395384929234': {'chapter': 'chapter48f'}, 'baz_run': {'course': 'root'}, } ) # only one course matches prob_location = loc_mapper().translate_locator_to_location(prob_locator) # default branch self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED)) # test get_course keyword prob_location = loc_mapper().translate_locator_to_location(prob_locator, get_course=True) self.assertEqual(prob_location, SlashSeparatedCourseKey(org, course, run)) # explicit branch prob_locator = prob_locator.for_branch(BRANCH_NAME_DRAFT) prob_location = loc_mapper().translate_locator_to_location(prob_locator) # Even though the problem was set as draft, we always return revision= KEY_REVISION_PUBLISHED to work # with old mongo/draft modulestores. self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED)) prob_locator = BlockUsageLocator( prob_course_key.for_branch('production'), block_type='problem', block_id='problem2' ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED)) # same for chapter except chapter cannot be draft in old system chap_locator = BlockUsageLocator( prob_course_key.for_branch('production'), block_type='chapter', block_id='chapter48f', ) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234')) # explicit branch chap_locator = chap_locator.for_branch(BRANCH_NAME_DRAFT) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234')) chap_locator = BlockUsageLocator( prob_course_key.for_branch('production'), block_type='chapter', block_id='chapter48f' ) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234')) # look for non-existent problem prob_locator2 = BlockUsageLocator( prob_course_key.for_branch(BRANCH_NAME_DRAFT), block_type='problem', block_id='problem3' ) prob_location = loc_mapper().translate_locator_to_location(prob_locator2) self.assertIsNone(prob_location, 'Found non-existent problem') # add a distractor course delta_run = 'delta_run' new_style_offering = '{}.{}'.format(course, delta_run) loc_mapper().create_map_entry( SlashSeparatedCourseKey(org, course, delta_run), new_style_org, new_style_offering, block_map={'abc123': {'problem': 'problem3'}} ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED))
def test_translate_locator(self): """ tests translate_locator_to_location(BlockUsageLocator) """ # lookup for non-existent course org = 'foo_org' course = 'bar_course' run = 'baz_run' new_style_org = '{}.geek_dept'.format(org) new_style_offering = '{}.{}'.format(course, run) prob_course_key = CourseLocator( org=new_style_org, offering=new_style_offering, branch='published', ) prob_locator = BlockUsageLocator( prob_course_key, block_type='problem', block_id='problem2', ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertIsNone(prob_location, 'found entry in empty map table') loc_mapper().create_map_entry( SlashSeparatedCourseKey(org, course, run), new_style_org, new_style_offering, block_map={ 'abc123': {'problem': 'problem2'}, '48f23a10395384929234': {'chapter': 'chapter48f'}, 'baz_run': {'course': 'root'}, } ) # only one course matches prob_location = loc_mapper().translate_locator_to_location(prob_locator) # default branch self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', None)) # test get_course keyword prob_location = loc_mapper().translate_locator_to_location(prob_locator, get_course=True) self.assertEqual(prob_location, SlashSeparatedCourseKey(org, course, run)) # explicit branch prob_locator = prob_locator.for_branch('draft') prob_location = loc_mapper().translate_locator_to_location(prob_locator) # Even though the problem was set as draft, we always return revision=None to work # with old mongo/draft modulestores. self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', None)) prob_locator = BlockUsageLocator( prob_course_key.for_branch('production'), block_type='problem', block_id='problem2' ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', None)) # same for chapter except chapter cannot be draft in old system chap_locator = BlockUsageLocator( prob_course_key.for_branch('production'), block_type='chapter', block_id='chapter48f', ) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234')) # explicit branch chap_locator = chap_locator.for_branch('draft') chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234')) chap_locator = BlockUsageLocator( prob_course_key.for_branch('production'), block_type='chapter', block_id='chapter48f' ) chap_location = loc_mapper().translate_locator_to_location(chap_locator) self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234')) # look for non-existent problem prob_locator2 = BlockUsageLocator( prob_course_key.for_branch('draft'), block_type='problem', block_id='problem3' ) prob_location = loc_mapper().translate_locator_to_location(prob_locator2) self.assertIsNone(prob_location, 'Found non-existent problem') # add a distractor course delta_run = 'delta_run' new_style_offering = '{}.{}'.format(course, delta_run) loc_mapper().create_map_entry( SlashSeparatedCourseKey(org, course, delta_run), new_style_org, new_style_offering, block_map={'abc123': {'problem': 'problem3'}} ) prob_location = loc_mapper().translate_locator_to_location(prob_locator) self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', None))