diff --git a/pyproject.toml b/pyproject.toml index 43bc952..84ae486 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "usf" -version = "0.1.2" +version = "0.2.0" description = "A lightweight Universal Schedule Format (USF) parser and generator." authors = [{ name = "USF-org", email = "USF-org@outlook.com" }] license = { text = "MIT" } diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..751f60a --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +jsonschema==4.0.0 \ No newline at end of file diff --git a/setup.py b/setup.py index 43ef90f..feaf578 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name="usf", - version="0.1.2", + version="0.2.0", packages=find_packages(), install_requires=[], python_requires=">=3.6", diff --git a/tests/test_usf.py b/tests/test_usf.py index dc37018..69941aa 100644 --- a/tests/test_usf.py +++ b/tests/test_usf.py @@ -22,7 +22,7 @@ def setUp(self): self.generator.add_schedule(1, "all", "Physics", 2) # 星期一,第二节,物理 # 生成 USF 数据 - self.usf_data = self.generator.generate_usf_data() + self.usf_data = self.generator.generate() def test_usf_generation(self): """测试 USF 生成""" @@ -38,7 +38,10 @@ def test_usf_generation(self): def test_usf_parser(self): """测试 USF 解析""" + # 将生成的 USF 数据转为 JSON 字符串 json_data = json.dumps(self.usf_data, indent=2) + + # 使用解析器解析数据 parser = USFParser(json_data) self.assertEqual(len(parser.get_subjects()), 2) @@ -63,7 +66,38 @@ def test_usf_validation(self): "subjects": self.usf_data["subjects"], "periods": self.usf_data["periods"] } - self.assertFalse(validator.validate(invalid_data)) + + # 这里我们添加了额外的错误处理来捕获无效数据的校验错误 + with self.assertRaises(jsonschema.exceptions.ValidationError): + validator.validate(invalid_data) + + def test_invalid_period(self): + """测试无效时间段""" + invalid_periods_data = { + "version": 1, + "subjects": self.usf_data["subjects"], + "periods": [["invalid", "format"]], + "timetable": self.usf_data["timetable"] + } + + # 使用校验器验证无效的时间段数据 + validator = USFValidator() + with self.assertRaises(jsonschema.exceptions.ValidationError): + validator.validate(invalid_periods_data) + + def test_invalid_subject(self): + """测试无效科目""" + invalid_subjects_data = { + "version": 1, + "subjects": {"InvalidSubject": {}}, + "periods": self.usf_data["periods"], + "timetable": self.usf_data["timetable"] + } + + # 使用校验器验证无效的科目数据 + validator = USFValidator() + with self.assertRaises(jsonschema.exceptions.ValidationError): + validator.validate(invalid_subjects_data) if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/usf/generator.py b/usf/generator.py index 3afd15d..91ad2d0 100644 --- a/usf/generator.py +++ b/usf/generator.py @@ -1,4 +1,5 @@ import json +import re class USFGenerator: def __init__(self, version=1): @@ -23,6 +24,9 @@ def add_subject(self, name, simplified_name=None, teacher=None, room=None): teacher (str, optional): Teacher's name. room (str, optional): Classroom. """ + if name in self.subjects: + raise ValueError(f"Subject '{name}' already exists.") + self.subjects[name] = { "simplified_name": simplified_name or name, "teacher": teacher or "", @@ -40,6 +44,10 @@ def add_period(self, start_time, end_time): Returns: int: Index of the added period (1-based). """ + time_pattern = "^(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$" + if not re.match(time_pattern, start_time) or not re.match(time_pattern, end_time): + raise ValueError(f"Invalid time format. Must be 'HH:MM:SS'.") + self.periods.append([start_time, end_time]) return len(self.periods) # Return 1-based index @@ -57,6 +65,9 @@ def add_schedule(self, day, week_type, subject, period_index): raise ValueError(f"Subject '{subject}' is not defined.") if period_index < 1 or period_index > len(self.periods): raise ValueError(f"Invalid period index {period_index}.") + if week_type not in ["all", "even", "odd"]: + raise ValueError(f"Invalid week type '{week_type}'. Must be 'all', 'even', or 'odd'.") + self.timetable.append([day, week_type, subject, period_index]) def generate(self): @@ -80,5 +91,8 @@ def save_to_file(self, filename): Args: filename (str): Output filename. """ - with open(filename, "w", encoding="utf-8") as f: - json.dump(self.generate(), f, indent=2, ensure_ascii=False) \ No newline at end of file + try: + with open(filename, "w", encoding="utf-8") as f: + json.dump(self.generate(), f, indent=2, ensure_ascii=False) + except Exception as e: + raise IOError(f"Failed to save USF data to {filename}: {e}") \ No newline at end of file diff --git a/usf/parser.py b/usf/parser.py index 97665c0..ef18265 100644 --- a/usf/parser.py +++ b/usf/parser.py @@ -8,8 +8,13 @@ def __init__(self, filename): Args: filename (str): Path to USF JSON file. """ - with open(filename, "r", encoding="utf-8") as f: - self.data = json.load(f) + try: + with open(filename, "r", encoding="utf-8") as f: + self.data = json.load(f) + except FileNotFoundError: + raise FileNotFoundError(f"File '{filename}' not found.") + except json.JSONDecodeError: + raise ValueError(f"Failed to decode JSON from the file '{filename}'.") def get_subjects(self): """Return the subjects dictionary.""" diff --git a/usf/validator.py b/usf/validator.py index 7999982..c529873 100644 --- a/usf/validator.py +++ b/usf/validator.py @@ -10,8 +10,13 @@ def __init__(self, schema_file="schema.json"): Args: schema_file (str, optional): Path to JSON Schema. Defaults to "schema.json". """ - with open(schema_file, "r", encoding="utf-8") as f: - self.schema = json.load(f) + try: + with open(schema_file, "r", encoding="utf-8") as f: + self.schema = json.load(f) + except FileNotFoundError: + raise FileNotFoundError(f"Schema file '{schema_file}' not found.") + except json.JSONDecodeError: + raise ValueError(f"Failed to decode JSON from the schema file '{schema_file}'.") def validate(self, data): """ @@ -23,6 +28,8 @@ def validate(self, data): Returns: bool: True if valid, raises an error if invalid. """ - validate(instance=data, schema=self.schema) - return True - \ No newline at end of file + try: + validate(instance=data, schema=self.schema) + except jsonschema.exceptions.ValidationError as e: + raise ValueError(f"USF data validation failed: {e.message}") + return True \ No newline at end of file