def test_string_single_field(self): exception = MissingRequiredFieldError("config file path", ["field1"], "model") expected_string = ( "\n****************************ERROR****************************\n" "File: config file path\n\n" "A model requires the following field:\n" " - field1\n\n" "For the missing field:\n" " - Is the field name spelt correctly?\n" " - Does the field have the correct value?\n") self.assertEqual(exception.__str__(), expected_string)
def handle(self, *args, **options): """Automatically called when the loadchapters command is given.""" factory = LoaderFactory() # Get structure and content files base_loader = BaseLoader() base_path = settings.CHAPTERS_CONTENT_BASE_PATH structure_file_path = os.path.join(base_path, base_loader.structure_dir, "structure.yaml") structure_file = base_loader.load_yaml_file(structure_file_path) if "glossary-folder" in structure_file: glossary_directory = structure_file["glossary-folder"] if glossary_directory is not None: factory.create_glossary_terms_loader( base_path=base_path, content_path=glossary_directory, ).load() chapters = structure_file.get("chapters", None) if chapters is None: raise MissingRequiredFieldError(structure_file_path, ["chapters"], "Application Structure") else: for chapter_slug in chapters: chapter_structure_file = "{}.yaml".format(chapter_slug) chapter_number = chapters[chapter_slug].get( "chapter-number", None) if chapter_number is None: raise MissingRequiredFieldError( structure_file_path, ["chapter_number"], "Application Structure for Chapter {}".format( chapter_slug)) if isinstance(chapter_number, int) is False: raise InvalidYAMLValueError( structure_file_path, "chapter-number - value '{}' is invalid".format( chapter_number), "chapter-number must be an integer value.") factory.create_chapter_loader( base_path=base_path, content_path=chapter_slug, chapter_number=chapter_number, structure_filename=chapter_structure_file, ).load() base_loader.log("All chapters loaded!") base_loader.log("")
def load(self): """Load the content for resources. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ resources_structure = self.load_yaml_file(self.structure_file_path) for (resource_slug, resource_structure) in resources_structure.items(): try: generator_module = resource_structure["generator-module"] resource_thumbnail = resource_structure[ "thumbnail-static-path"] resource_copies = resource_structure["copies"] except KeyError: raise MissingRequiredFieldError( self.structure_file_path, ["generator-module", "thumbnail-static-path", "copies"], "Resource") resource_translations = self.get_blank_translation_dictionary() content_filename = "{}.md".format(resource_slug) content_translations = self.get_markdown_translations( content_filename) for language, content in content_translations.items(): resource_translations[language][ "content"] = content.html_string resource_translations[language]["name"] = content.title # Remove .py extension if given if generator_module.endswith(".py"): generator_module = generator_module[:-3] # Check module can be imported get_resource_generator(generator_module, QueryDict()) # Check thumbnail exists if not finders.find(resource_thumbnail): error_text = "Thumbnail image {} for resource {} could not be found." raise FileNotFoundError( error_text.format(resource_thumbnail, resource_slug)) # Check copies value is boolean if not isinstance(resource_copies, bool): raise InvalidYAMLValueError(self.structure_file_path, "copies", "'true' or 'false'") resource = Resource( slug=resource_slug, generator_module=generator_module, thumbnail_static_path=resource_thumbnail, copies=resource_copies, ) self.populate_translations(resource, resource_translations) self.mark_translation_availability( resource, required_fields=["name", "content"]) resource.save() self.log("Added Resource: {}".format(resource.name)) self.log("All resources loaded!\n")
def check_template(self, page_data, type): """Check template in page_data is valid. Args: page_data (dict): Dictionary of page data. type (str): Name of type of page. Returns: A valid template as string. Raises: MissingRequiredFieldError: If template value not given. InvalidYAMLValueError: If invalid template path given. """ try: template = page_data["template"] except (TypeError, KeyError): raise MissingRequiredFieldError(self.structure_file_path, [ "template", ], type) try: get_template(template) except TemplateDoesNotExist: raise InvalidYAMLValueError(self.structure_file_path, "template ({})".format(template), "A valid template file path") return template
def load(self): """Load the content for resources. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ resources_structure = self.load_yaml_file( self.BASE_PATH.format(self.structure_file)) for (resource_slug, resource_structure) in resources_structure.items(): try: resource_name = resource_structure["name"] resource_template = resource_structure["webpage-template"] resource_view = resource_structure["generation-view"] resource_thumbnail = resource_structure[ "thumbnail-static-path"] resource_copies = resource_structure["copies"] except: raise MissingRequiredFieldError() resource = Resource( slug=resource_slug, name=resource_name, webpage_template=resource_template, generation_view=resource_view, thumbnail_static_path=resource_thumbnail, copies=resource_copies, ) resource.save() self.log("Added Resource: {}".format(resource.name)) self.log("All resources loaded!\n")
def load(self): """Load Classic CS Unplugged pages. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ classic_pages = self.load_yaml_file(self.structure_file_path) for (slug, page_data) in classic_pages.items(): try: name = page_data["name"] except (TypeError, KeyError): raise MissingRequiredFieldError( self.structure_file_path, [ "name", ], "Classic CS Unplugged page" ) redirect_url = urljoin("https://classic.csunplugged.org/", slug) classic_page = ClassicPage( slug=slug, name=name, redirect=redirect_url, ) classic_page.save() self.log("Added Classic CS Unplugged page: {}".format(name)) self.log("All Classic CS Unplugged pages loaded!\n")
def handle(self, *args, **options): """Automatically called when the loadcurriculumguides command is given.""" factory = LoaderFactory() # Get structure and content files base_loader = BaseLoader() base_path = settings.CURRICULUM_GUIDES_CONTENT_BASE_PATH structure_file_path = os.path.join(base_path, base_loader.structure_dir, "structure.yaml") structure_file = base_loader.load_yaml_file(structure_file_path) curriculum_guides = structure_file.get("curriculum_guides", None) if curriculum_guides is None: raise MissingRequiredFieldError(structure_file_path, ["curriculum_guides"], "Application Structure") else: for curriculum_guide_slug in curriculum_guides: curriculum_guide_structure_file = "{}.yaml".format( curriculum_guide_slug) curriculum_guide_number = curriculum_guides[ curriculum_guide_slug].get("curriculum-guide-number", None) if curriculum_guide_number is None: raise MissingRequiredFieldError( structure_file_path, ["curriculum_guide_number"], "Application Structure for Curriculum Guide {}".format( curriculum_guide_slug)) if isinstance(curriculum_guide_number, int) is False: raise InvalidYAMLValueError( structure_file_path, "curriculum-guide-number - value '{}' is invalid". format(curriculum_guide_number), "curriculum-guide-number must be an integer value.") factory.create_curriculum_guide_loader( base_path=base_path, content_path=curriculum_guide_slug, curriculum_guide_number=curriculum_guide_number, structure_filename=curriculum_guide_structure_file, ).load() base_loader.log("All curriculum guides loaded!") base_loader.log("")
def load(self): """Load the content for age groups. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ age_groups_structure = self.load_yaml_file(self.structure_file_path) # Use same name as structure file for translations age_groups_translations = self.get_yaml_translations( self.structure_filename) for (age_group_slug, age_group_data) in age_groups_structure.items(): if age_group_data is None: raise MissingRequiredFieldError(self.structure_file_path, ["min_age", "max_age"], "Age Range") translations = age_groups_translations.get(age_group_slug, dict()) group_min_age = age_group_data.get("min_age", None) if group_min_age is None: raise MissingRequiredFieldError(self.structure_file_path, ["min_age"], "Age Range") group_max_age = age_group_data.get("max_age", None) if group_max_age is None: raise MissingRequiredFieldError(self.structure_file_path, ["max_age"], "Age Range") # Create area objects and save to database age_group = AgeGroup( slug=age_group_slug, ages=(int(group_min_age), int(group_max_age)), ) self.populate_translations(age_group, translations) self.mark_translation_availability(age_group, required_fields=["description"]) age_group.save() self.log("Added age group: {}".format(age_group.__str__())) self.log("All age groups loaded!\n")
def load(self): """Load the content for resources. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ resources_structure = self.load_yaml_file(self.structure_file_path) for (resource_slug, resource_structure) in resources_structure.items(): try: resource_name = resource_structure["name"] resource_template = resource_structure["webpage-template"] generator_module = resource_structure["generator-module"] resource_thumbnail = resource_structure[ "thumbnail-static-path"] resource_copies = resource_structure["copies"] except KeyError: raise MissingRequiredFieldError(self.structure_file_path, [ "name", "webpage-template", "generator-module", "thumbnail-static-path", "copies" ], "Resource") # Check resource template file exists open(os.path.join("templates", resource_template), encoding="UTF-8") # Remove .py extension if given if generator_module.endswith(".py"): generator_module = generator_module[:-3] # Check module can be imported get_resource_generator(generator_module, QueryDict()) # Check thumbnail exists if not finders.find(resource_thumbnail): raise FileNotFoundError # Check copies value is boolean if not isinstance(resource_copies, bool): raise InvalidConfigValueError(self.structure_file_path, "copies", "'true' or 'false'") resource = Resource( slug=resource_slug, name=resource_name, webpage_template=resource_template, generator_module=generator_module, thumbnail_static_path=resource_thumbnail, copies=resource_copies, ) resource.save() self.log("Added Resource: {}".format(resource.name)) self.log("All resources loaded!\n")
def load(self): """Load the content for age groups. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ age_groups_structure = self.load_yaml_file( os.path.join(self.BASE_PATH, self.structure_file_path)) for (age_group_slug, age_group_data) in age_groups_structure.items(): if age_group_data is None: raise MissingRequiredFieldError(self.structure_file_path, ["min_age", "max_age"], "Age Range") group_min_age = age_group_data.get("min_age", None) if group_min_age is None: raise MissingRequiredFieldError(self.structure_file_path, ["min_age"], "Age Range") group_max_age = age_group_data.get("max_age", None) if group_max_age is None: raise MissingRequiredFieldError(self.structure_file_path, ["max_age"], "Age Range") group_description = age_group_data.get("description", None) # Create area objects and save to database age_group = AgeGroup( slug=age_group_slug, ages=(int(group_min_age), int(group_max_age)), description=group_description, ) age_group.save() self.log("Added age group: {}".format(age_group.__str__())) self.log("All age groups loaded!\n")
def load(self): """Load the content for a curriculum guide. Raises: MissingRequiredFieldError: When a config (yaml) file is missing a required field. """ curriculum_guide_structure = self.load_yaml_file( self.structure_file_path) sections = curriculum_guide_structure.get("sections", None) if sections is None: raise MissingRequiredFieldError(self.structure_file_path, ["sections"], "CurriculumGuide") curriculum_guide_translations = self.get_blank_translation_dictionary() introduction_filename = "{}.md".format(self.curriculum_guide_slug) introduction_translations = self.get_markdown_translations( introduction_filename) for language, content in introduction_translations.items(): curriculum_guide_translations[language][ "introduction"] = content.html_string curriculum_guide_translations[language]["name"] = content.title # Create curriculum guide object and save to the db curriculum_guide = CurriculumGuide( slug=self.curriculum_guide_slug, number=self.curriculum_guide_number, ) self.populate_translations(curriculum_guide, curriculum_guide_translations) self.mark_translation_availability( curriculum_guide, required_fields=["name", "introduction"]) curriculum_guide.save() self.log("Added curriculum guide: {}".format(curriculum_guide.name)) # Load curriculum guide sections content_path, structure_filename = os.path.split(sections) self.factory.create_curriculum_guide_section_loader( curriculum_guide, base_path=self.base_path, content_path=os.path.join(self.content_path, content_path), structure_filename=structure_filename).load()
def load(self): """Load general pages. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ general_pages = self.load_yaml_file(self.structure_file_path) for (slug, page_data) in general_pages.items(): try: name = page_data["name"] template = page_data["template"] url_name = page_data["url-name"] except (TypeError, KeyError): raise MissingRequiredFieldError(self.structure_file_path, [ "name", "template", "url-name", ], "General page") # Check template is valid try: get_template(template) except TemplateDoesNotExist: raise InvalidYAMLValueError(self.structure_file_path, "template", "A valid template file path") # Check URL name is valid try: reverse(url_name) except NoReverseMatch: raise InvalidYAMLValueError( self.structure_file_path, "url-name", "A URL name listed in 'csunplugged/general/urls.py'") general_page = GeneralPage( slug=slug, name=name, template=template, url_name=url_name, ) general_page.save() self.log("Added general page: {}".format(name)) self.log("All general pages loaded!\n")
def handle(self, *args, **options): """Automatically called when the loadactivities command is given. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ lite_load = options.get("lite_load") factory = LoaderFactory() # Get structure and content files base_loader = BaseLoader() base_path = settings.ACTIVITIES_CONTENT_BASE_PATH structure_file_path = os.path.join(base_path, base_loader.structure_dir, "activities.yaml") structure_file = base_loader.load_yaml_file(structure_file_path) if structure_file.get("activities", None) is None or not isinstance( structure_file["activities"], dict): raise MissingRequiredFieldError(structure_file_path, ["activities"], "At Home") else: for activity_slug, activity_data in structure_file[ "activities"].items(): activity_path = activity_slug activity_structure_file = "{}.yaml".format(activity_slug) factory.create_activity_loader( base_path=base_path, content_path=activity_path, structure_filename=activity_structure_file, lite_loader=lite_load, activity_data=activity_data, ).load()
def load(self): """Load the content for learning outcomes. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ learning_outcomes = self.load_yaml_file( os.path.join(self.BASE_PATH, self.structure_file_path)) for (outcome_slug, outcome_data) in learning_outcomes.items(): if ("text" not in outcome_data) or (outcome_data["text"] is None): raise MissingRequiredFieldError(self.structure_file_path, ["text"], "Learning Outcome") # Create outcome objects and save to db outcome = LearningOutcome(slug=outcome_slug, text=outcome_data["text"]) outcome.save() # Add curriculum areas curriculum_area_slugs = outcome_data.get("curriculum-areas", []) for curriculum_area_slug in curriculum_area_slugs: try: curriculum_area = CurriculumArea.objects.get( slug=curriculum_area_slug) outcome.curriculum_areas.add(curriculum_area) except: raise KeyNotFoundError(self.structure_file_path, curriculum_area_slug, "Curriculum Areas") self.log("Added learning outcome: {}".format(outcome.__str__())) self.log("All learning outcomes loaded!\n")
def load(self): """Load the content for a single lesson. Raises: KeyNotFoundError: when no object can be found with the matching attribute. InvalidConfigValueError: when provided value is not valid. MissingRequiredFieldError: when a value for a required model field cannot be found in the config file. """ lessons_structure = self.load_yaml_file( self.lessons_structure_file_path) for (lesson_slug, lesson_structure) in lessons_structure.items(): if lesson_structure is None: raise MissingRequiredFieldError( self.lessons_structure_file_path, ["number"], "Lesson") # Build the file path to the lesson"s md file file_path = os.path.join(self.BASE_PATH, "lessons", "{}.md".format(lesson_slug)) lesson_content = self.convert_md_file( file_path, self.lessons_structure_file_path, ) if "computational-thinking-links" in lesson_structure: file_name = lesson_structure["computational-thinking-links"] file_path = os.path.join(self.BASE_PATH, "lessons", file_name) ct_links_content = self.convert_md_file( file_path, self.lessons_structure_file_path, heading_required=False, remove_title=False, ) ct_links = ct_links_content.html_string else: ct_links = None if "duration" in lesson_structure: lesson_duration = lesson_structure["duration"] else: lesson_duration = None heading_tree = None if lesson_content.heading_tree: heading_tree = convert_heading_tree_to_dict( lesson_content.heading_tree) if "programming-challenges-description" in lesson_structure: file_name = lesson_structure[ "programming-challenges-description"] file_path = os.path.join(self.BASE_PATH, "lessons", file_name) programming_description_content = self.convert_md_file( file_path, self.lessons_structure_file_path, heading_required=False, remove_title=False, ) programming_description = programming_description_content.html_string else: programming_description = None classroom_resources = lesson_structure.get("classroom-resources", None) if isinstance(classroom_resources, list): for classroom_resource in classroom_resources: if not isinstance(classroom_resource, str): raise InvalidConfigValueError( self.lessons_structure_file_path, "classroom-resources list item", "A string describing the classroom resource.") elif len(classroom_resource) > 100: raise InvalidConfigValueError( self.lessons_structure_file_path, "classroom-resources list item", "Item description must be less than 100 characters." ) elif classroom_resources is not None: raise InvalidConfigValueError(self.lessons_structure_file_path, "classroom-resources", "List of strings.") lesson = self.topic.lessons.create( unit_plan=self.unit_plan, slug=lesson_slug, name=lesson_content.title, duration=lesson_duration, content=lesson_content.html_string, computational_thinking_links=ct_links, heading_tree=heading_tree, programming_challenges_description=programming_description, classroom_resources=classroom_resources, ) lesson.save() # Add programming challenges if "programming-challenges" in lesson_structure: programming_challenge_slugs = lesson_structure[ "programming-challenges"] if programming_challenge_slugs is not None: # Check all slugs are valid for programming_challenge_slug in programming_challenge_slugs: try: ProgrammingChallenge.objects.get( slug=programming_challenge_slug, topic=self.topic) except: raise KeyNotFoundError( self.lessons_structure_file_path, programming_challenge_slug, "Programming Challenges") # Store number of challenge in relationship with lesson. # If three linked challenges have numbers 1.1, 4.2, and 4.5 # They will be stored as 1.1, 2.1, and 2.2 respectively. # Order challenges for numbering. programming_challenges = ProgrammingChallenge.objects.filter( slug__in=programming_challenge_slugs, topic=self.topic).order_by("challenge_set_number", "challenge_number") # Setup variables for numbering. display_set_number = 0 last_set_number = -1 display_number = 0 last_number = -1 # For each challenge, increment number variables if original # numbers are different. for programming_challenge in programming_challenges: if programming_challenge.challenge_set_number > last_set_number: display_set_number += 1 display_number = 0 last_number = -1 if programming_challenge.challenge_number > last_number: display_number += 1 last_set_number = programming_challenge.challenge_set_number last_number = programming_challenge.challenge_number # Create and save relationship between lesson and # challenge that contains challenge number. relationship = ProgrammingChallengeNumber( programming_challenge=programming_challenge, lesson=lesson, challenge_set_number=display_set_number, challenge_number=display_number, ) relationship.save() # Add learning outcomes if "learning-outcomes" in lesson_structure: learning_outcome_slugs = lesson_structure["learning-outcomes"] if learning_outcome_slugs is not None: for learning_outcome_slug in learning_outcome_slugs: try: learning_outcome = LearningOutcome.objects.get( slug=learning_outcome_slug) lesson.learning_outcomes.add(learning_outcome) except: raise KeyNotFoundError( self.lessons_structure_file_path, learning_outcome_slug, "Learning Outcomes") # Add generated resources if "generated-resources" in lesson_structure: resources = lesson_structure["generated-resources"] if resources is not None: for (resource_slug, resource_data) in resources.items(): if resource_data is None: raise MissingRequiredFieldError( self.lessons_structure_file_path, ["description"], "Generated Resource") try: resource = Resource.objects.get(slug=resource_slug) except: raise KeyNotFoundError( self.lessons_structure_file_path, resource_slug, "Resources") resource_description = resource_data.get( "description", None) if resource_description is None: raise MissingRequiredFieldError( self.lessons_structure_file_path, ["description"], "Generated Resource") relationship = ResourceDescription( resource=resource, lesson=lesson, description=resource_description) relationship.save() self.log("Added lesson: {}".format(lesson.__str__()), 2)
def load(self): """Load the content for unit plans. Raise: KeyNotFoundError: when no object can be found with the matching attribute. MissingRequiredFieldError: when a value for a required model field cannot be found in the config file. """ unit_plan_structure = self.load_yaml_file(self.structure_file_path) unit_plan_translations = self.get_blank_translation_dictionary() content_filename = "{}.md".format(self.unit_plan_slug) content_translations = self.get_markdown_translations(content_filename) for language, content in content_translations.items(): unit_plan_translations[language]["content"] = content.html_string unit_plan_translations[language]["name"] = content.title if content.heading_tree: heading_tree = convert_heading_tree_to_dict( content.heading_tree) unit_plan_translations[language]["heading_tree"] = heading_tree if "computational-thinking-links" in unit_plan_structure: ct_links_filename = unit_plan_structure[ "computational-thinking-links"] ct_links_translations = self.get_markdown_translations( ct_links_filename, heading_required=False, remove_title=False, ) for language, content in ct_links_translations.items(): unit_plan_translations[language][ "computational_thinking_links"] = content.html_string unit_plan = self.topic.unit_plans.create( slug=self.unit_plan_slug, languages=list(content_translations.keys()), ) self.populate_translations(unit_plan, unit_plan_translations) self.mark_translation_availability(unit_plan, required_fields=["name", "content"]) unit_plan.save() self.log("Added unit plan: {}".format(unit_plan.name), 1) # Load the lessons for the unit plan # Get path to lesson yaml lessons_yaml = unit_plan_structure.get("lessons", None) if lessons_yaml is None: raise MissingRequiredFieldError(self.structure_file_path, ["lessons", "age-groups"], "Unit Plan") lesson_path, lesson_structure_file = os.path.split(lessons_yaml) # Call the loader to save the lessons into the db self.factory.create_lessons_loader( self.topic, unit_plan, content_path=os.path.join(self.content_path, lesson_path), structure_filename=lesson_structure_file, base_path=self.base_path, ).load() # Create AgeGroup and assign to lessons age_groups = unit_plan_structure.get("age-groups", None) if age_groups is None: raise MissingRequiredFieldError(self.structure_file_path, ["lessons", "age-groups"], "Unit Plan") for (age_group_slug, age_group_data) in age_groups.items(): try: age_group = AgeGroup.objects.get(slug=age_group_slug) except ObjectDoesNotExist: raise KeyNotFoundError(self.structure_file_path, age_group_slug, "Age Range") if age_group_data is None: raise MissingRequiredFieldError(self.structure_file_path, ["lesson keys"], "Unit Plan") for (lesson_slug, lesson_data) in age_group_data.items(): try: lesson = Lesson.objects.get(slug=lesson_slug) except ObjectDoesNotExist: raise KeyNotFoundError(self.structure_file_path, lesson_slug, "Lesson") if lesson_data is None or lesson_data.get("number", None) is None: raise MissingRequiredFieldError(self.structure_file_path, ["number"], "Unit Plan") else: lesson_number = lesson_data.get("number", None) relationship = LessonNumber( age_group=age_group, lesson=lesson, number=lesson_number, ) relationship.save()
def load(self): """Load the content for programming challenges. Raises: CouldNotFindMarkdownFileError: when no file can be found with the provided filename. KeyNotFoundError: when no object can be found with the matching attribute. MissingRequiredFieldError: when no object can be found with the matching attribute. """ programming_challenges_structure = self.load_yaml_file(self.structure_file_path) for (challenge_slug, challenge_structure) in programming_challenges_structure.items(): if challenge_structure is None: raise MissingRequiredFieldError( self.structure_file_path, ["challenge-set-number", "challenge-number", "programming-languages", "difficulty-level"], "Programming Challenge" ) # Retrieve required variables from md file challenge_set_number = challenge_structure.get("challenge-set-number", None) challenge_number = challenge_structure.get("challenge-number", None) challenge_languages = challenge_structure.get("programming-languages", None) challenge_difficulty = challenge_structure.get("difficulty-level", None) if None in [challenge_set_number, challenge_number, challenge_languages, challenge_difficulty]: raise MissingRequiredFieldError( self.structure_file_path, ["challenge-set-number", "challenge-number", "programming-languages", "difficulty-level"], "Programming Challenge" ) # Build the path to the programming challenge's folder file_path = os.path.join( self.BASE_PATH, challenge_slug, "{}.md" ) challenge_content = self.convert_md_file( file_path.format(challenge_slug), self.structure_file_path ) challenge_extra_challenge_file = challenge_structure.get("extra-challenge", None) if challenge_extra_challenge_file: challenge_extra_challenge_content = self.convert_md_file( file_path.format(challenge_extra_challenge_file[:-3]), self.structure_file_path, heading_required=False, ) challenge_extra_challenge = challenge_extra_challenge_content.html_string else: challenge_extra_challenge = None try: difficulty_level = ProgrammingChallengeDifficulty.objects.get( level=challenge_difficulty ) except: raise KeyNotFoundError( self.structure_file_path, challenge_difficulty, "Programming Challenge Difficulty" ) programming_challenge = self.topic.programming_challenges.create( slug=challenge_slug, name=challenge_content.title, challenge_set_number=challenge_set_number, challenge_number=challenge_number, content=challenge_content.html_string, extra_challenge=challenge_extra_challenge, difficulty=difficulty_level ) programming_challenge.save() LOG_TEMPLATE = "Added programming challenge: {}" self.log(LOG_TEMPLATE.format(programming_challenge.name), 1) for language in challenge_languages: if language is None: raise MissingRequiredFieldError( self.structure_file_path, ["challenge-set-number", "challenge-number", "programming-languages", "difficulty-level"], "Programming Challenge" ) try: language_object = ProgrammingChallengeLanguage.objects.get( slug=language ) except: raise KeyNotFoundError( self.structure_file_path, language, "Programming Challenge Language" ) expected_result_content = self.convert_md_file( file_path.format( "{}-expected".format(language) ), self.structure_file_path, heading_required=False ) # Load example solution solution_content = self.convert_md_file( file_path.format( "{}-solution".format(language) ), self.structure_file_path, heading_required=False ) # Load hint if given try: hint_content = self.convert_md_file( file_path.format( "{}-hints".format(language) ), self.structure_file_path, heading_required=False ) except CouldNotFindMarkdownFileError: hint_content = None implementation = ProgrammingChallengeImplementation( expected_result=expected_result_content.html_string, hints=None if hint_content is None else hint_content.html_string, solution=solution_content.html_string, language=language_object, challenge=programming_challenge, topic=self.topic ) implementation.save() LOG_TEMPLATE = "Added language implementation: {}" self.log(LOG_TEMPLATE.format(implementation.language), 2) if "learning-outcomes" in challenge_structure: learning_outcomes = challenge_structure["learning-outcomes"] if learning_outcomes is not None: for learning_outcome_slug in learning_outcomes: try: learning_outcome = LearningOutcome.objects.get( slug=learning_outcome_slug ) programming_challenge.learning_outcomes.add(learning_outcome) except: raise KeyNotFoundError( self.structure_file_path, learning_outcome_slug, "Learning Outcome")
def load(self): """Load the content for a section. Raises: MissingRequiredFieldError: When a config (yaml) file is missing a required field. """ chapter_sections_structure = self.load_yaml_file(self.structure_file_path) section_numbers = [] for (section_slug, section_structure) in chapter_sections_structure.items(): if section_structure is None: raise MissingRequiredFieldError( self.structure_file_path, ["section-number"], "ChapterSection" ) section_number = section_structure.get("section-number", None) if section_number is None: raise MissingRequiredFieldError( self.structure_file_path, ["section-number"], "ChapterSection" ) if isinstance(section_number, int) is False: raise InvalidYAMLValueError( self.structure_file_path, "section-number - value '{}' is invalid".format(section_number), "section-number must be an integer value." ) section_numbers.append(section_number) chapter_section_translations = self.get_blank_translation_dictionary() content_filename = "{}.md".format(section_slug) content_translations = self.get_markdown_translations(content_filename) for language, content in content_translations.items(): chapter_section_translations[language]["content"] = content.html_string chapter_section_translations[language]["name"] = content.title chapter_section = self.chapter.chapter_sections.create( slug=section_slug, number=section_number, languages=list(content_translations.keys()), ) self.populate_translations(chapter_section, chapter_section_translations) self.mark_translation_availability(chapter_section, required_fields=["name", "content"]) chapter_section.save() self.log("Added chapter section: {}".format(chapter_section.name), 1) check_interactives( content_translations[get_default_language()].required_files["interactives"], self.structure_file_path, self.chapter, ) # Save chapter section headings self.factory.create_chapter_section_heading_loader( chapter_section, content_translations, base_path=self.base_path, structure_filename=self.structure_file_path, ).load() # assumes first section number is always 1 for counter, section_number in enumerate(section_numbers, 1): if section_number != counter: raise InvalidYAMLValueError( self.structure_file_path, "section-number - value '{}' is invalid".format(section_number), "section-numbers must be in sequential order. The next expected number was '{}'.".format(counter) )
def handle(self, *args, **options): """Automatically called when the loadresources command is given. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ factory = LoaderFactory() # Get structure and content files base_loader = BaseLoader() BASE_PATH = "topics/content/en/" structure_file_path = os.path.join(BASE_PATH, "structure.yaml") structure_file = base_loader.load_yaml_file(structure_file_path) if "curriculum-areas" in structure_file: curriculum_areas_structure_file_path = structure_file[ "curriculum-areas"] if curriculum_areas_structure_file_path is not None: factory.create_curriculum_areas_loader( curriculum_areas_structure_file_path, BASE_PATH).load() if "learning-outcomes" in structure_file: learning_outcomes_structure_file_path = structure_file[ "learning-outcomes"] if learning_outcomes_structure_file_path is not None: factory.create_learning_outcomes_loader( learning_outcomes_structure_file_path, BASE_PATH).load() if "programming-challenges-structure" in structure_file: programming_challenges_structure_file_path = structure_file[ "programming-challenges-structure"] if programming_challenges_structure_file_path is not None: factory.create_programming_challenges_structure_loader( programming_challenges_structure_file_path, BASE_PATH).load() if "glossary-folder" in structure_file: glossary_folder_path = structure_file["glossary-folder"] if glossary_folder_path is not None: factory.create_glossary_terms_loader(glossary_folder_path, structure_file_path, BASE_PATH).load() if structure_file["age-groups"] is None: raise MissingRequiredFieldError(structure_file_path, ["age-groups"], "Application Structure") else: age_groups_path = structure_file["age-groups"] if age_groups_path is not None: factory.create_age_groups_loader(age_groups_path, BASE_PATH).load() if structure_file["topics"] is None: raise MissingRequiredFieldError(structure_file_path, ["topics"], "Application Structure") for topic in structure_file["topics"]: topic_structure_file = "{0}/{0}.yaml".format(topic) factory.create_topic_loader(topic_structure_file, BASE_PATH).load()
def load(self): """Load the content for a topic. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ topic_structure = self.load_yaml_file(self.structure_file_path) unit_plans = topic_structure.get("unit-plans", None) if unit_plans is None: raise MissingRequiredFieldError(self.structure_file_path, ["unit-plans"], "Topic") topic_translations = self.get_blank_translation_dictionary() content_filename = "{}.md".format(self.topic_slug) content_translations = self.get_markdown_translations(content_filename) for language, content in content_translations.items(): topic_translations[language]["content"] = content.html_string topic_translations[language]["name"] = content.title if "other-resources" in topic_structure and topic_structure[ "other-resources"] is not None: other_resources_filename = topic_structure["other-resources"] other_resources_translations = self.get_markdown_translations( other_resources_filename) for language, content in other_resources_translations.items(): topic_translations[language][ "other_resources"] = content.html_string # Check if icon is given if "icon" in topic_structure: topic_icon = topic_structure["icon"] if topic_icon is not None: find_image_files([topic_icon], self.structure_file_path) else: topic_icon = None else: topic_icon = None # Create topic objects and save to the db topic = Topic( slug=self.topic_slug, icon=topic_icon, ) self.populate_translations(topic, topic_translations) self.mark_translation_availability(topic, required_fields=["name", "content"]) topic.save() self.log("Added Topic: {}".format(topic.name)) # Load programming challenges if "programming-challenges" in topic_structure: programming_challenges_structure_file_path = topic_structure[ "programming-challenges"] if programming_challenges_structure_file_path is not None: programming_challenges_path, structure_filename = os.path.split( programming_challenges_structure_file_path) self.factory.create_programming_challenges_loader( topic, base_path=self.base_path, content_path=os.path.join(self.content_path, programming_challenges_path), structure_filename=structure_filename).load() # Load unit plans for unit_plan_file_path in unit_plans: content_path, structure_filename = os.path.split( unit_plan_file_path) self.factory.create_unit_plan_loader( topic, base_path=self.base_path, content_path=os.path.join(self.content_path, content_path), structure_filename=structure_filename).load() if "curriculum-integrations" in topic_structure: curriculum_integrations_structure_file_path = topic_structure[ "curriculum-integrations"] if curriculum_integrations_structure_file_path is not None: curriculum_integrations_path, structure_filename = os.path.split( curriculum_integrations_structure_file_path) self.factory.create_curriculum_integrations_loader( topic, base_path=self.base_path, content_path=os.path.join(self.content_path, curriculum_integrations_path), structure_filename=structure_filename).load() self.log("")
def load(self): """Load the content for curriculum integrations. Raise: KeyNotFoundError: when no object can be found with the matching attribute. MissingRequiredFieldError: when a value for a required model field cannot be found in the config file. """ structure = self.load_yaml_file(self.structure_file_path) for (integration_slug, integration_data) in structure.items(): if integration_data is None: raise MissingRequiredFieldError(self.structure_file_path, ["number", "curriculum-areas"], "Curriculum Integration") integration_number = integration_data.get("number", None) integration_curriculum_areas = integration_data.get( "curriculum-areas", None) if None in [integration_number, integration_curriculum_areas]: raise MissingRequiredFieldError(self.structure_file_path, ["number", "curriculum-areas"], "Curriculum Integration") integration_content = self.convert_md_file( os.path.join(self.BASE_PATH, "{}.md".format(integration_slug)), self.structure_file_path) integration = self.topic.curriculum_integrations.create( slug=integration_slug, number=integration_number, name=integration_content.title, content=integration_content.html_string, ) integration.save() # Add curriculum areas for curriculum_area_slug in integration_curriculum_areas: try: curriculum_area = CurriculumArea.objects.get( slug=curriculum_area_slug) integration.curriculum_areas.add(curriculum_area) except: raise KeyNotFoundError(self.structure_file_path, curriculum_area_slug, "Curriculum Areas") # Add prerequisite lessons if "prerequisite-lessons" in integration_data: prerequisite_lessons = integration_data["prerequisite-lessons"] if prerequisite_lessons is not None: for (unit_plan_slug, lessons) in prerequisite_lessons.items(): if lessons is None: raise MissingRequiredFieldError( self.structure_file_path, ["unit-plan"], "Prerequisite Lesson") for lesson_slug in lessons: try: lesson = Lesson.objects.get(slug=lesson_slug) integration.prerequisite_lessons.add(lesson) except: raise KeyNotFoundError( self.structure_file_path, lesson_slug, "Lessons") self.log( "Added curriculum integration: {}".format(integration.name), 1)
def load(self): """Load the content for unit plans. Raise: KeyNotFoundError: when no object can be found with the matching attribute. MissingRequiredFieldError: when a value for a required model field cannot be found in the config file. """ unit_plan_structure = self.load_yaml_file(self.structure_file_path) # Convert the content to HTML unit_plan_content = self.convert_md_file( os.path.join(self.BASE_PATH, "{}.md".format(self.unit_plan_slug)), self.structure_file_path) heading_tree = None if unit_plan_content.heading_tree: heading_tree = convert_heading_tree_to_dict( unit_plan_content.heading_tree) if "computational-thinking-links" in unit_plan_structure: file_name = unit_plan_structure["computational-thinking-links"] file_path = os.path.join(self.BASE_PATH, file_name) ct_links_content = self.convert_md_file( file_path, self.structure_file_path, heading_required=False, remove_title=False, ) ct_links = ct_links_content.html_string else: ct_links = None unit_plan = self.topic.unit_plans.create( slug=self.unit_plan_slug, name=unit_plan_content.title, content=unit_plan_content.html_string, heading_tree=heading_tree, computational_thinking_links=ct_links, ) unit_plan.save() self.log("Added unit plan: {}".format(unit_plan.name), 1) # Load the lessons for the unit plan # Get path to lesson yaml lessons_yaml = unit_plan_structure.get("lessons", None) if lessons_yaml is None: raise MissingRequiredFieldError(self.structure_file_path, ["lessons", "age-groups"], "Unit Plan") lessons_structure_file_path = os.path.join(self.BASE_PATH, lessons_yaml) # Call the loader to save the lessons into the db self.factory.create_lessons_loader(lessons_structure_file_path, self.topic, unit_plan, self.BASE_PATH).load() # Create AgeGroup and assign to lessons age_groups = unit_plan_structure.get("age-groups", None) if age_groups is None: raise MissingRequiredFieldError(self.structure_file_path, ["lessons", "age-groups"], "Unit Plan") for (age_group_slug, age_group_data) in age_groups.items(): try: age_group = AgeGroup.objects.get(slug=age_group_slug) except: raise KeyNotFoundError(self.structure_file_path, age_group_slug, "Age Range") if age_group_data is None: raise MissingRequiredFieldError(self.structure_file_path, ["lesson keys"], "Unit Plan") for (lesson_slug, lesson_data) in age_group_data.items(): try: lesson = Lesson.objects.get(slug=lesson_slug) except: raise KeyNotFoundError(self.structure_file_path, lesson_slug, "Lesson") if lesson_data is None or lesson_data.get("number", None) is None: raise MissingRequiredFieldError(self.structure_file_path, ["number"], "Unit Plan") else: lesson_number = lesson_data.get("number", None) relationship = LessonNumber( age_group=age_group, lesson=lesson, number=lesson_number, ) relationship.save()
def load(self): """Load the content for programming challenges. Raises: CouldNotFindMarkdownFileError: when no file can be found with the provided filename. KeyNotFoundError: when no object can be found with the matching attribute. MissingRequiredFieldError: when no object can be found with the matching attribute. """ programming_challenges_structure = self.load_yaml_file( self.structure_file_path) for (challenge_slug, challenge_structure) in programming_challenges_structure.items(): if challenge_structure is None: raise MissingRequiredFieldError(self.structure_file_path, [ "challenge-set-number", "challenge-number", "programming-languages", "difficulty-level" ], "Programming Challenge") challenge_translations = self.get_blank_translation_dictionary() # Retrieve required variables from md file challenge_set_number = challenge_structure.get( "challenge-set-number", None) challenge_number = challenge_structure.get("challenge-number", None) challenge_prog_languages = challenge_structure.get( "programming-languages", None) challenge_difficulty = challenge_structure.get( "difficulty-level", None) if None in [ challenge_set_number, challenge_number, challenge_prog_languages, challenge_difficulty ]: raise MissingRequiredFieldError(self.structure_file_path, [ "challenge-set-number", "challenge-number", "programming-languages", "difficulty-level" ], "Programming Challenge") content_filename = "{0}.md".format(challenge_slug) content_translations = self.get_markdown_translations( os.path.join(challenge_slug, content_filename)) for language, content in content_translations.items(): challenge_translations[language][ "content"] = content.html_string challenge_translations[language]["name"] = content.title challenge_extra_challenge_file = challenge_structure.get( "extra-challenge", None) if challenge_extra_challenge_file: extra_challenge_translations = self.get_markdown_translations( os.path.join(challenge_slug, challenge_extra_challenge_file), heading_required=False, ) for language, content in extra_challenge_translations.items(): challenge_translations[language][ "extra_challenge"] = content.html_string try: difficulty_level = ProgrammingChallengeDifficulty.objects.get( level=challenge_difficulty) except ObjectDoesNotExist: raise KeyNotFoundError(self.structure_file_path, challenge_difficulty, "Programming Challenge Difficulty") programming_challenge = self.topic.programming_challenges.create( slug=challenge_slug, challenge_set_number=challenge_set_number, challenge_number=challenge_number, difficulty=difficulty_level) self.populate_translations(programming_challenge, challenge_translations) self.mark_translation_availability( programming_challenge, required_fields=["name", "content"]) programming_challenge.save() LOG_TEMPLATE = "Added programming challenge: {}" self.log(LOG_TEMPLATE.format(programming_challenge.name), 1) for prog_language in challenge_prog_languages: if prog_language is None: raise MissingRequiredFieldError(self.structure_file_path, [ "challenge-set-number", "challenge-number", "programming-languages", "difficulty-level" ], "Programming Challenge") try: prog_language_object = ProgrammingChallengeLanguage.objects.get( slug=prog_language) except ObjectDoesNotExist: raise KeyNotFoundError(self.structure_file_path, prog_language, "Programming Challenge Language") implementation_translations = self.get_blank_translation_dictionary( ) filename_template = os.path.join( challenge_slug, "{}-{{}}.md".format(prog_language)) expected_result_translations = self.get_markdown_translations( filename_template.format("expected"), heading_required=False) for language, content in expected_result_translations.items(): implementation_translations[language][ "expected_result"] = content.html_string solution_translations = self.get_markdown_translations( filename_template.format("solution"), heading_required=False) for language, content in solution_translations.items(): implementation_translations[language][ "solution"] = content.html_string hints_translations = self.get_markdown_translations( filename_template.format("hints"), heading_required=False, required=False) for language, content in hints_translations.items(): implementation_translations[language][ "hints"] = content.html_string implementation = ProgrammingChallengeImplementation( language=prog_language_object, challenge=programming_challenge, topic=self.topic) self.populate_translations(implementation, implementation_translations) self.mark_translation_availability( implementation, required_fields=["solution", "expected_result"]) implementation.save() LOG_TEMPLATE = "Added language implementation: {}" self.log(LOG_TEMPLATE.format(implementation.language), 2) test_cases = challenge_structure.get("test-cases", None) if (test_cases is not None): for (testcase_id, testcase_type) in test_cases.items(): test_case_translations = self.get_blank_translation_dictionary( ) testcase_filename_template = os.path.join( challenge_slug, 'test-cases', "test-case-{}-{{}}.txt".format(testcase_id)) testcase_input = open(self.get_localised_file( "en", testcase_filename_template.format(testcase_type)), encoding='UTF-8').read() testcase_output = open(self.get_localised_file( "en", testcase_filename_template.format("output")), encoding='UTF-8').read() test_case = TestCase(number=testcase_id, test_input=testcase_input, expected_output=testcase_output, question_type=testcase_type, challenge=programming_challenge) required_fields = [ 'test_input', 'expected_output', 'question_type' ] self.populate_translations(test_case, test_case_translations) self.mark_translation_availability( test_case, required_fields=required_fields) test_case.save() LOG_TEMPLATE = "Added Programming Challenge Test Case: {}" self.log(LOG_TEMPLATE.format(testcase_id), 2) if "learning-outcomes" in challenge_structure: learning_outcomes = challenge_structure["learning-outcomes"] if learning_outcomes is not None: for learning_outcome_slug in learning_outcomes: try: learning_outcome = LearningOutcome.objects.get( slug=learning_outcome_slug) programming_challenge.learning_outcomes.add( learning_outcome) except ObjectDoesNotExist: raise KeyNotFoundError(self.structure_file_path, learning_outcome_slug, "Learning Outcome")
def load(self): """Load the content for curriculum areas. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ curriculum_areas_structure = self.load_yaml_file( os.path.join(self.BASE_PATH, self.structure_file_path)) for (curriculum_area_slug, curriculum_area_data) in curriculum_areas_structure.items(): if curriculum_area_data is None: raise MissingRequiredFieldError(self.structure_file_path, ["name"], "Curriculum Area") curriculum_area_name = curriculum_area_data.get("name", None) if curriculum_area_name is None: raise MissingRequiredFieldError(self.structure_file_path, ["name"], "Curriculum Area") curriculum_area_colour = curriculum_area_data.get("colour", None) if curriculum_area_colour is None: raise MissingRequiredFieldError(self.structure_file_path, ["colour"], "Curriculum Area") curriculum_area_number = curriculum_area_data.get("number", None) if curriculum_area_number is None: raise MissingRequiredFieldError(self.structure_file_path, ["number"], "Curriculum Area") # Create area objects and save to database new_area = CurriculumArea( slug=curriculum_area_slug, name=curriculum_area_name, colour=curriculum_area_colour, number=curriculum_area_number, ) new_area.save() self.log("Added curriculum area: {}".format(new_area.__str__())) # Create children curriculum areas with reference to parent if "children" in curriculum_area_data: children_curriculum_areas = curriculum_area_data["children"] if children_curriculum_areas is None: raise MissingRequiredFieldError(self.structure_file_path, ["slug"], "Child Curriculum Area") for (child_slug, child_data) in children_curriculum_areas.items(): if child_data is None: raise MissingRequiredFieldError( self.structure_file_path, ["name"], "Child Curriculum Area") child_name = child_data.get("name", None) if child_name is None: raise MissingRequiredFieldError( self.structure_file_path, ["name"], "Child Curriculum Area") new_child = CurriculumArea( slug=child_slug, name=child_name, colour=curriculum_area_colour, number=curriculum_area_number, parent=new_area, ) new_child.save() self.log( "Added child curriculum area: {}".format( new_child.__str__()), 1) self.log("All curriculum areas loaded!\n")
def handle(self, *args, **options): """Automatically called when the loadresources command is given. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ factory = LoaderFactory() lite_load = options.get("lite_load") # Get structure and content files base_loader = BaseLoader() base_path = settings.TOPICS_CONTENT_BASE_PATH structure_file_path = os.path.join(base_path, base_loader.structure_dir, "structure.yaml") structure_file = base_loader.load_yaml_file(structure_file_path) if "curriculum-areas" in structure_file: curriculum_areas_structure_file_path = structure_file[ "curriculum-areas"] if curriculum_areas_structure_file_path is not None: curriculum_areas_path, structure_filename = os.path.split( curriculum_areas_structure_file_path) factory.create_curriculum_areas_loader( base_path=base_path, content_path=curriculum_areas_path, structure_filename=structure_filename).load() if "learning-outcomes" in structure_file: learning_outcomes_structure_file_path = structure_file[ "learning-outcomes"] if learning_outcomes_structure_file_path is not None: learning_outcomes_path, structure_filename = os.path.split( learning_outcomes_structure_file_path) factory.create_learning_outcomes_loader( base_path=base_path, content_path=learning_outcomes_path, structure_filename=structure_filename).load() if "programming-challenges-structure" in structure_file: programming_challenges_structure_file_path = structure_file[ "programming-challenges-structure"] if programming_challenges_structure_file_path is not None: programming_challenges_path, structure_filename = os.path.split( programming_challenges_structure_file_path) factory.create_programming_challenges_structure_loader( base_path=base_path, content_path=programming_challenges_path, structure_filename=structure_filename).load() if "classroom-resources" in structure_file: classroom_resources_structure_file_path = structure_file[ "classroom-resources"] if classroom_resources_structure_file_path is not None: classroom_resources_path, structure_filename = os.path.split( classroom_resources_structure_file_path) factory.create_classroom_resources_loader( base_path=base_path, content_path=classroom_resources_path, structure_filename=structure_filename).load() if "glossary-folder" in structure_file: glossary_folder_path = structure_file["glossary-folder"] if glossary_folder_path is not None: factory.create_glossary_terms_loader( base_path=base_path, content_path=glossary_folder_path, ).load() age_groups_structure_file_path = structure_file.get("age-groups", None) if age_groups_structure_file_path is None: raise MissingRequiredFieldError(structure_file_path, ["age-groups"], "Application Structure") else: age_groups_path, structure_filename = os.path.split( age_groups_structure_file_path) factory.create_age_groups_loader( content_path=age_groups_path, base_path=base_path, structure_filename=structure_filename).load() if structure_file.get("topics", None) is None or not isinstance( structure_file["topics"], list): raise MissingRequiredFieldError(structure_file_path, ["topics"], "Application Structure") else: for topic in structure_file["topics"]: topic_path = topic topic_structure_file = "{}.yaml".format(topic) factory.create_topic_loader( base_path=base_path, content_path=topic_path, structure_filename=topic_structure_file, lite_loader=lite_load, ).load()
def load(self): """Load the content for structure of programming challenges. Raises: MissingRequiredFieldError: when no object can be found with the matching attribute. """ structure = self.load_yaml_file( os.path.join( self.BASE_PATH, self.structure_file_path ) ) languages = structure.get("languages", None) difficulty_levels = structure.get("difficulties", None) if None in [languages, difficulty_levels]: raise MissingRequiredFieldError( self.structure_file_path, ["lanugages", "difficulties"], "Programming Challenge Structure" ) for (language, language_data) in languages.items(): if language_data is None: raise MissingRequiredFieldError( self.structure_file_path, ["name", "number"], "Programming Challenge Language" ) # Check for required fields language_name = language_data.get("name", None) language_number = language_data.get("number", None) if language_name is None or language_number is None: raise MissingRequiredFieldError( self.structure_file_path, ["name", "number"], "Programming Challenge Language" ) # Check if icon is given if "icon" in language_data: language_icon = language_data["icon"] else: language_icon = None new_language = ProgrammingChallengeLanguage( slug=language, name=language_name, number=language_number, icon=language_icon ) new_language.save() self.log("Added programming langauge: {}".format(new_language.__str__())) for (difficulty, difficulty_data) in difficulty_levels.items(): if difficulty_data is None: raise MissingRequiredFieldError( self.structure_file_path, ["name"], "Programming Challenge Difficulty" ) difficulty_name = difficulty_data.get("name", None) if difficulty_name is None: raise MissingRequiredFieldError( self.structure_file_path, ["name"], "Programming Challenge Difficulty" ) new_difficulty = ProgrammingChallengeDifficulty( level=difficulty, name=difficulty_name ) new_difficulty.save() self.log("Added programming difficulty level: {}".format(new_difficulty.__str__())) self.log("")
def test_attributes(self): exception = MissingRequiredFieldError("config file path", ["field1", "field2"], "model") self.assertEqual(exception.config_file_path, "config file path") self.assertEqual(exception.required_fields, ["field1", "field2"]) self.assertEqual(exception.model, "model")
def load(self): """Load the content for curriculum areas. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ curriculum_areas_structure = self.load_yaml_file( self.structure_file_path) curriculum_areas_translations = self.get_yaml_translations( self.structure_filename, required_fields=["name"], required_slugs=curriculum_areas_structure.keys()) for (curriculum_area_slug, curriculum_area_data) in curriculum_areas_structure.items(): if curriculum_area_data is None: raise MissingRequiredFieldError(self.structure_file_path, ["name"], "Curriculum Area") translations = curriculum_areas_translations.get( curriculum_area_slug, dict()) curriculum_area_colour = curriculum_area_data.get("colour", None) if curriculum_area_colour is None: raise MissingRequiredFieldError(self.structure_file_path, ["colour"], "Curriculum Area") curriculum_area_number = curriculum_area_data.get("number", None) if curriculum_area_number is None: raise MissingRequiredFieldError(self.structure_file_path, ["number"], "Curriculum Area") # Create area objects and save to database new_area = CurriculumArea( slug=curriculum_area_slug, colour=curriculum_area_colour, number=curriculum_area_number, ) self.populate_translations(new_area, translations) self.mark_translation_availability(new_area, required_fields=["name"]) new_area.save() self.log("Added curriculum area: {}".format(new_area.__str__())) # Create children curriculum areas with reference to parent if "children" in curriculum_area_data: children_curriculum_areas = curriculum_area_data["children"] if children_curriculum_areas is None: raise MissingRequiredFieldError(self.structure_file_path, ["slug"], "Child Curriculum Area") for child_slug in children_curriculum_areas: translations = curriculum_areas_translations.get( child_slug, dict()) new_child = CurriculumArea( slug=child_slug, colour=curriculum_area_colour, number=curriculum_area_number, parent=new_area, ) self.populate_translations(new_child, translations) self.mark_translation_availability( new_child, required_fields=["name"]) new_child.save() self.log( "Added child curriculum area: {}".format( new_child.__str__()), 1) self.log("All curriculum areas loaded!\n")
def load(self): """Load the content for structure of programming challenges. Raises: MissingRequiredFieldError: when no object can be found with the matching attribute. """ structure = self.load_yaml_file(self.structure_file_path) prog_languages = structure.get("languages", None) difficulty_levels = structure.get("difficulties", None) if None in [prog_languages, difficulty_levels]: raise MissingRequiredFieldError( self.structure_file_path, ["lanugages", "difficulties"], "Programming Challenge Structure" ) # Add "-languages" to the structure filename prog_languages_translation_filename = "{}-languages.yaml".format( os.path.splitext(self.structure_filename)[0] ) prog_languages_translations = self.get_yaml_translations( prog_languages_translation_filename, required_slugs=prog_languages.keys(), required_fields=["name"] ) for (prog_language, prog_language_data) in prog_languages.items(): if prog_language_data is None: raise MissingRequiredFieldError( self.structure_file_path, ["number"], "Programming Challenge Language" ) # Check for required fields prog_language_number = prog_language_data.get("number", None) if prog_language_number is None: raise MissingRequiredFieldError( self.structure_file_path, ["number"], "Programming Challenge Language" ) # Check if icon is given if "icon" in prog_language_data: prog_language_icon = prog_language_data["icon"] else: prog_language_icon = None new_prog_language = ProgrammingChallengeLanguage( slug=prog_language, number=prog_language_number, icon=prog_language_icon ) translations = prog_languages_translations.get(prog_language, dict()) self.populate_translations(new_prog_language, translations) self.mark_translation_availability(new_prog_language, required_fields=["name"]) new_prog_language.save() self.log("Added programming language: {}".format(new_prog_language.__str__())) # Add "-languages" to the structure filename difficulties_translation_filename = "{}-difficulties.yaml".format( os.path.splitext(self.structure_filename)[0] ) difficulties_translations = self.get_yaml_translations( difficulties_translation_filename, required_slugs=difficulty_levels, required_fields=["name"], ) for level, difficulty_slug in enumerate(difficulty_levels): new_difficulty = ProgrammingChallengeDifficulty( level=level, ) translations = difficulties_translations.get(difficulty_slug, dict()) self.populate_translations(new_difficulty, translations) self.mark_translation_availability(new_difficulty, required_fields=["name"]) new_difficulty.save() self.log("Added programming difficulty level: {}".format(new_difficulty.__str__())) self.log("")
def load(self): """Load the content for an activity. Raise: MissingRequiredFieldError: when no object can be found with the matching attribute. """ activity_translations = self.get_blank_translation_dictionary() try: order_number = self.activity_data['order-number'] activity_icon = self.activity_data['icon'] except KeyError: raise MissingRequiredFieldError( self.structure_file_path, [ "order-number", "icon" ], "Activity" ) # Check if icon is available find_image_files([activity_icon], self.structure_file_path) # Introduction content content_translations = self.get_markdown_translations(INTRODUCTION_FILENAME) for language, content in content_translations.items(): activity_translations[language]['name'] = content.title activity_translations[language]['introduction'] = content.html_string activity_steps_translations = self.get_activity_step_translations() for language, content in activity_steps_translations.items(): activity_translations[language]['activity_steps'] = content activity_extra_info_md_file_path = self.get_localised_file( language, ACTIVITY_EXTRA_INFORMATION_FILENMAE, ) activity_extra_info_exists = os.path.exists(activity_extra_info_md_file_path) if activity_extra_info_exists: activity_extra_info_translations = self.get_markdown_translations( ACTIVITY_EXTRA_INFORMATION_FILENMAE, heading_required=False, remove_title=False, ) for language, content in activity_extra_info_translations.items(): activity_translations[language]['activity_extra_information'] = content.html_string inside_computer_translations = self.get_markdown_translations( INSIDE_THE_COMPUTER_FILENAME, heading_required=False, remove_title=False, ) for language, content in inside_computer_translations.items(): activity_translations[language]['inside_the_computer'] = content.html_string project_md_file_path = self.get_localised_file( language, PROJECT_FILENAME, ) project_exists = os.path.exists(project_md_file_path) if project_exists: project_translations = self.get_markdown_translations( PROJECT_FILENAME, heading_required=False, remove_title=False, ) for language, content in project_translations.items(): activity_translations[language]['project'] = content.html_string more_information_translations = self.get_markdown_translations( MORE_INFORMATION_FILENAME, heading_required=False, remove_title=False, ) for language, content in more_information_translations.items(): activity_translations[language]['more_information'] = content.html_string # Create or update activity objects and save to the database activity, created = Activity.objects.update_or_create( slug=self.activity_slug, defaults={ 'order_number': order_number, 'icon': activity_icon, } ) self.populate_translations(activity, activity_translations) self.mark_translation_availability(activity, required_fields=['name', 'introduction']) activity.save() if created: self.log('Added Activity: {}'.format(activity.name)) else: self.log('Updated Activity: {}'.format(activity.name)) # structure_filename = os.path.join(unit_plan_file_path) self.factory.create_challenge_loader( activity, base_path=self.base_path, content_path=self.content_path, structure_filename=self.structure_filename, lite_loader=self.lite_loader, ).load()