class ScenarioResult(object): uuid = related.UUIDField() case = related.ChildField(Case, required=None) scenario = related.ChildField(Namespace, required=None) success = related.BooleanField(default=True) step_results = related.SequenceField(StepResult, default=[]) suite = related.ChildField(Suite, required=False)
class Company(object): name = related.StringField() uuid = related.UUIDField() email = related.RegexField("[^@]+@[^@]+", required=False) is_active = related.BooleanField(required=False) url = related.URLField(required=False) meta = related.ChildField(dict, required=False) nicknames = related.SequenceField(str, required=False) temperature = related.FloatField(required=False) guess = related.SetField(int, required=False) established = related.DateField('%m/%d/%Y', required=False) closed = related.DateField(required=False) # default formatter (%Y-%m-%d)
class Exam: """Represents a writable exam""" meta_uuid = related.UUIDField() generated_at = related.DateTimeField(default=datetime.now(), required=False) questions = related.SequenceField(ExamQuestion, required=False) title = related.StringField('') description = related.StringField(required=False) was_user_completed = related.BooleanField(False, required=False) user_name = related.StringField(required=False) completed_at = related.DateTimeField(required=False) def save(self, path: str): with open(path, "w") as file: related.to_yaml(self, file) def clear(self): """ Clears this Exam instance from any user-input """ self.was_user_completed = False self.user_name = None self.completed_at = None for question in self.questions: for ans in question.answers: ans.is_selected = False @property def max_score(self): return sum(q.points for q in self.questions) def get_score(self, meta, question_callback: Callable = None) -> int: """ Calculates this Exam's total score. Args question_callback: called for each graded question with its score """ if meta is None: return 0 score = 0 for question in self.questions: question_meta = meta.find_question(question.id) points = question.grade(question_meta) if question_callback: question_callback(question, points) score += points return score
class Case(object): scenarios = related.SequenceField(Namespace) name = related.StringField(required=False, default=None) steps = related.SequenceField(Step, default=[]) format = related.StringField(default="1.0") host = related.StringField(required=False) tags = related.SequenceField(str, required=False) headers = related.ChildField(Namespace, required=False) file_path = related.StringField(default=None) is_valid = related.BooleanField(default=True) uuid = related.UUIDField() @classmethod def prep_scenarios(cls, original, dir_path): updated = [] counter = 1 if isinstance(original, str): original = utils.parse_into_rows_of_dicts(original) for scenario in original or [{}]: if isinstance(scenario, str): scenario_file_path = os.path.join(dir_path, scenario) scenario = related.from_yaml(open(scenario_file_path), object_pairs_hook=dict) name = scenario.get("__name__") or "Scenario #%s" % counter scenario["__name__"] = name counter += 1 updated.append(scenario) return updated @classmethod def loads(cls, content, file_path=None): try: as_dict = related.from_yaml(content, file_path=file_path, object_pairs_hook=dict) scenarios = as_dict.get("scenarios", []) dir_path = os.path.dirname(file_path) as_dict['scenarios'] = cls.prep_scenarios(scenarios, dir_path) return related.to_model(Case, as_dict) except Exception as e: # raise e get_logger().error("Failed to Load Case", file_path=file_path, error=str(e)) return Case(file_path=file_path, is_valid=False, scenarios=[]) def is_active(self, included, excluded): has_steps = len(self.steps) > 0 is_included = not included or utils.overlap(included, self.tags) is_excluded = excluded and utils.overlap(excluded, self.tags) return self.is_valid and has_steps and is_included and not is_excluded @property def dir_path(self): return os.path.dirname(self.file_path)
class DetectorUUID: uuid = related.UUIDField()
class MyChild(object): my_int = related.IntegerField(key="int") my_float = related.FloatField(key="float") my_uuid = related.UUIDField(key="uuid")
class ProblemSet: """Stores all question metadata and defaults""" uuid = related.UUIDField(required=False) title = related.StringField('') questions = related.MappingField(ExamQuestionMeta, 'id', required=False) question_defaults = related.ChildField(ExamQuestionMeta, ExamQuestionMeta.from_defaults(), required=False) def create_question(self, **kwargs) -> ExamQuestionMeta: """Creates a new Question from defaults""" return ExamQuestionMeta.from_defaults(self.question_defaults.__dict__, kwargs) def insert_question(self, allow_edit: bool, id: str, **kwargs) -> ExamQuestionMeta: found_question = self.find_question(id) if found_question: if not allow_edit: raise KeyError("Question with specified `id` already exists") sum_dict = combine_dictionaries(found_question.__dict__, kwargs) new_question = self.create_question(**sum_dict) else: new_question = self.create_question(**kwargs) self.questions[id] = new_question return new_question def find_question(self, id: str) -> ExamQuestionMeta: """ Returns the question with specified `id` if it exists; otherwise None """ return self.questions.get(id, None) def generate_exam(self, num_questions: int, description: str, title: str = None) -> Exam: """ Creates an Exam instance from randomly selected questions and answers Args: num_questions: the number of questions to include description: exam description shown to user title: short exam title """ questions_meta = weighted_random(self.questions.items(), lambda q: q[1].likelihood, num_questions) questions = [ ExamQuestion.from_meta(id, meta) for id, meta in questions_meta ] now = datetime.now() return Exam(meta_uuid=self.uuid, generated_at=now, title=title or self.title, questions=questions, description=description) def ensure_exam_compatibility(self, exam: Exam) -> None: """ Checks whether the `exam` was created from this problem set. Raises SchemeError: if the `exam` isn't compatible """ def fail(reason): raise SchemeError( f"Problem set `{self.title}` does not match the exam `{self.title}` ({reason})" ) if self.uuid != exam.meta_uuid: fail('UUID') # check for missing questions for question in exam.questions: if self.find_question(question.id) is None: fail(f"missing question: {question.id}") def save(self, path: str) -> None: """ Saves this object instance as YAML to the specified path """ self.validate() with open(path, "w") as file: related.to_yaml(self, file, suppress_empty_values=True, suppress_map_key_values=True) def validate(self): """Validates object state""" for key, question in self.questions.items(): question.validate() @staticmethod def from_file(path: str): with open(path, "r") as file: obj = related.from_yaml(file, ProblemSet) obj.validate() return obj