2510회 채점자료 업데이트 / 스크립트 블럭 순서 재정렬 방식 변경
This commit is contained in:
@@ -47,8 +47,8 @@ def copy_ent_files(source_root, target_root):
|
|||||||
|
|
||||||
# 사용법
|
# 사용법
|
||||||
|
|
||||||
source_directory = r"D:\project\Entry\Entry-Scoring\시험자료\2509\A" # 원본 디렉토리 경로
|
source_directory = r"D:\project\data\CAS_제2510회 정기\제2510회 코딩활용능력 2급 정기 답안파일" # 원본 디렉토리 경로
|
||||||
target_directory = r".\ent\2509_CAT_3_A"
|
target_directory = r".\ent\2510_CAS_2_A"
|
||||||
# target_directory_a = r"./output/A" # '1교시'의 타겟 경로
|
# target_directory_a = r"./output/A" # '1교시'의 타겟 경로
|
||||||
# target_directory_b = r"./output/B" # '2교시'의 타겟 경로
|
# target_directory_b = r"./output/B" # '2교시'의 타겟 경로
|
||||||
# target_directory_c = r"./output/C" # '3교시'의 타겟 경로
|
# target_directory_c = r"./output/C" # '3교시'의 타겟 경로
|
||||||
|
|||||||
@@ -50,8 +50,9 @@ def process_ent_files(ent_dir, output_dir):
|
|||||||
|
|
||||||
# 실행 예
|
# 실행 예
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_names = ["2509_CAT_3_A"]
|
# test_names = ["2509_CAT_3_A"]
|
||||||
# test_names = ["2508_CAS_2_A","2508_CAS_2_B"]
|
# test_names = ["2508_CAS_2_A","2508_CAS_2_B"]
|
||||||
|
test_names = ["2510_CAS_2_A"]
|
||||||
for test_name in test_names:
|
for test_name in test_names:
|
||||||
ent_dir = f".\\ent\\{test_name}"
|
ent_dir = f".\\ent\\{test_name}"
|
||||||
output_dir = f".\\output\\{test_name}"
|
output_dir = f".\\output\\{test_name}"
|
||||||
|
|||||||
BIN
251002_2509_CAT_3_A_채점결과.xlsx
Normal file
BIN
251002_2509_CAT_3_A_채점결과.xlsx
Normal file
Binary file not shown.
BIN
251030_2510_CAS_2_A_채점결과.xlsx
Normal file
BIN
251030_2510_CAS_2_A_채점결과.xlsx
Normal file
Binary file not shown.
BIN
251031_2510_CAS_2_A_채점결과.xlsx
Normal file
BIN
251031_2510_CAS_2_A_채점결과.xlsx
Normal file
Binary file not shown.
BIN
251103_2510_CAS_2_A_채점결과.xlsx
Normal file
BIN
251103_2510_CAS_2_A_채점결과.xlsx
Normal file
Binary file not shown.
BIN
251104_2510_CAS_2_A_채점결과.xlsx
Normal file
BIN
251104_2510_CAS_2_A_채점결과.xlsx
Normal file
Binary file not shown.
BIN
251105_2510_CAS_2_A_TEST.xlsx
Normal file
BIN
251105_2510_CAS_2_A_TEST.xlsx
Normal file
Binary file not shown.
BIN
251105_2510_CAS_2_A_채점결과.xlsx
Normal file
BIN
251105_2510_CAS_2_A_채점결과.xlsx
Normal file
Binary file not shown.
1008
correct/2510_CAS_2_A.json
Normal file
1008
correct/2510_CAS_2_A.json
Normal file
File diff suppressed because it is too large
Load Diff
223
logs/cat.log
223
logs/cat.log
@@ -34,3 +34,226 @@ Traceback (most recent call last):
|
|||||||
File "D:\project\Entry\Entry-Scoring\main.py", line 162, in process_project
|
File "D:\project\Entry\Entry-Scoring\main.py", line 162, in process_project
|
||||||
total_points += question_points
|
total_points += question_points
|
||||||
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'
|
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'
|
||||||
|
[2025-10-30 16:24:04] [ERROR] [main:301] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: unsupported operand type(s) for +=: 'int' and 'NoneType'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 296, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 162, in process_project
|
||||||
|
total_points += question_points
|
||||||
|
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'
|
||||||
|
[2025-10-30 16:26:32] [ERROR] [main:301] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: unsupported operand type(s) for +=: 'float' and 'NoneType'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 296, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 212, in process_project
|
||||||
|
total_points += block_points
|
||||||
|
TypeError: unsupported operand type(s) for +=: 'float' and 'NoneType'
|
||||||
|
[2025-10-31 17:08:00] [ERROR] [main:322] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 'NoneType' object is not iterable
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 317, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 167, in process_project
|
||||||
|
for block in block_list
|
||||||
|
^^^^^^^^^^
|
||||||
|
TypeError: 'NoneType' object is not iterable
|
||||||
|
[2025-10-31 17:14:04] [ERROR] [main:324] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: unhashable type: 'list'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 319, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 168, in process_project
|
||||||
|
if block.get("answer") in target_event_answers
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
TypeError: unhashable type: 'list'
|
||||||
|
[2025-10-31 17:17:42] [ERROR] [main:327] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: unhashable type: 'list'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 322, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 171, in process_project
|
||||||
|
if answer in target_event_answers: # 조건에 맞는지 확인
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
TypeError: unhashable type: 'list'
|
||||||
|
[2025-10-31 17:51:14] [ERROR] [main:360] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 'list' object has no attribute 'get'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 355, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 234, in process_project
|
||||||
|
script_data = reorder_script_by_event_order(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 149, in reorder_script_by_event_order
|
||||||
|
if script.get("type") == event_type:
|
||||||
|
^^^^^^^^^^
|
||||||
|
AttributeError: 'list' object has no attribute 'get'
|
||||||
|
[2025-10-31 17:56:20] [ERROR] [main:360] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 'list' object has no attribute 'get'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 355, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 234, in process_project
|
||||||
|
script_data = reorder_script_by_event_order(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 149, in reorder_script_by_event_order
|
||||||
|
if script.get("type") == event_type:
|
||||||
|
^^^^^^^^^^
|
||||||
|
AttributeError: 'list' object has no attribute 'get'
|
||||||
|
[2025-10-31 17:56:40] [ERROR] [main:360] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 'list' object has no attribute 'get'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 355, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 234, in process_project
|
||||||
|
script_data = reorder_script_by_event_order(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 149, in reorder_script_by_event_order
|
||||||
|
if script.get("type") == event_type:
|
||||||
|
^^^^^^^^^^
|
||||||
|
AttributeError: 'list' object has no attribute 'get'
|
||||||
|
[2025-10-31 17:58:18] [ERROR] [main:361] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 'list' object has no attribute 'get'
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 356, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 235, in process_project
|
||||||
|
script_data = reorder_script_by_event_order(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 150, in reorder_script_by_event_order
|
||||||
|
if script.get("type") == event_type:
|
||||||
|
^^^^^^^^^^
|
||||||
|
AttributeError: 'list' object has no attribute 'get'
|
||||||
|
[2025-11-03 16:09:35] [ERROR] [main:399] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: list indices must be integers or slices, not str
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 394, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 270, in process_project
|
||||||
|
script_data = reorder_script_all_cases(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 167, in reorder_script_all_cases
|
||||||
|
type_map.setdefault(s["type"], []).append(s)
|
||||||
|
~^^^^^^^^
|
||||||
|
TypeError: list indices must be integers or slices, not str
|
||||||
|
[2025-11-03 17:15:12] [ERROR] [main:433] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 0
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 428, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 310, in process_project
|
||||||
|
block_elements = find_element(single_script, block_path)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 33, in find_element
|
||||||
|
for match in jsonpath_expr.find(item):
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 268, in find
|
||||||
|
for subdata in self.left.find(datum)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 270, in find
|
||||||
|
for submatch in self.right.find(subdata)]
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 680, in find
|
||||||
|
return self._find_base(datum, create=False)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 692, in _find_base
|
||||||
|
return [DatumInContext(datum.value[self.index], path=self, context=datum)]
|
||||||
|
~~~~~~~~~~~^^^^^^^^^^^^
|
||||||
|
KeyError: 0
|
||||||
|
[2025-11-03 17:20:20] [ERROR] [main:417] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 0
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 412, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 300, in process_project
|
||||||
|
block_elements = find_element(data, block_path)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 33, in find_element
|
||||||
|
for match in jsonpath_expr.find(item):
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 268, in find
|
||||||
|
for subdata in self.left.find(datum)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 270, in find
|
||||||
|
for submatch in self.right.find(subdata)]
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 680, in find
|
||||||
|
return self._find_base(datum, create=False)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 692, in _find_base
|
||||||
|
return [DatumInContext(datum.value[self.index], path=self, context=datum)]
|
||||||
|
~~~~~~~~~~~^^^^^^^^^^^^
|
||||||
|
KeyError: 0
|
||||||
|
[2025-11-03 17:21:39] [ERROR] [main:407] 🚫Error processing ./output/2510_CAS_2_A/2510_CAS_2_A(정답)\project.json: 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 402, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 288, in process_project
|
||||||
|
block_elements = find_list_element(data, block_path)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 48, in find_list_element
|
||||||
|
result.append([match.value for match in jsonpath_expr.find(data)])
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 268, in find
|
||||||
|
for subdata in self.left.find(datum)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 270, in find
|
||||||
|
for submatch in self.right.find(subdata)]
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 680, in find
|
||||||
|
return self._find_base(datum, create=False)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "d:\project\Entry\Entry-Scoring\.venv\Lib\site-packages\jsonpath_ng\jsonpath.py", line 692, in _find_base
|
||||||
|
return [DatumInContext(datum.value[self.index], path=self, context=datum)]
|
||||||
|
~~~~~~~~~~~^^^^^^^^^^^^
|
||||||
|
KeyError: 1
|
||||||
|
[2025-11-04 15:36:56] [ERROR] [main:423] 🚫Error processing ./output/2510_CAS_2_A/코딩활용능력2급(엔트리)-000139-성지환\project.json: 'NoneType' object is not iterable
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 418, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 268, in process_project
|
||||||
|
script_data = reorder_script_all_cases(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 167, in reorder_script_all_cases
|
||||||
|
for s in script_json:
|
||||||
|
^^^^^^^^^^^
|
||||||
|
TypeError: 'NoneType' object is not iterable
|
||||||
|
[2025-11-04 16:20:44] [ERROR] [main:423] 🚫Error processing ./output/2510_CAS_2_A/코딩활용능력2급(엔트리)-000139-성지환\project.json: 'NoneType' object is not iterable
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 418, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 268, in process_project
|
||||||
|
script_data = reorder_script_all_cases(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 167, in reorder_script_all_cases
|
||||||
|
for s in script_json:
|
||||||
|
^^^^^^^^^^^
|
||||||
|
TypeError: 'NoneType' object is not iterable
|
||||||
|
[2025-11-04 17:11:33] [ERROR] [main:423] 🚫Error processing ./output/2510_CAS_2_A/코딩활용능력2급(엔트리)-000139-성지환\project.json: 'NoneType' object is not iterable
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 418, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 268, in process_project
|
||||||
|
script_data = reorder_script_all_cases(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 167, in reorder_script_all_cases
|
||||||
|
for s in script_json:
|
||||||
|
^^^^^^^^^^^
|
||||||
|
TypeError: 'NoneType' object is not iterable
|
||||||
|
[2025-11-05 16:02:42] [ERROR] [main:423] 🚫Error processing ./output/00_test/코딩활용능력2급(엔트리)-000139-성지환\project.json: 'NoneType' object is not iterable
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 418, in main
|
||||||
|
points = process_project(project_data, scoring_data)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 268, in process_project
|
||||||
|
script_data = reorder_script_all_cases(script_json, block_event_order)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "D:\project\Entry\Entry-Scoring\main.py", line 167, in reorder_script_all_cases
|
||||||
|
for s in script_json:
|
||||||
|
^^^^^^^^^^^
|
||||||
|
TypeError: 'NoneType' object is not iterable
|
||||||
|
|||||||
175
main.py
175
main.py
@@ -1,6 +1,5 @@
|
|||||||
from jsonpath_ng.ext import parse
|
from jsonpath_ng.ext import parse
|
||||||
import json
|
import json
|
||||||
from itertools import chain
|
|
||||||
import os
|
import os
|
||||||
import pandas as pd # 추가된 import
|
import pandas as pd # 추가된 import
|
||||||
import unicodedata # 상단에 import 추가
|
import unicodedata # 상단에 import 추가
|
||||||
@@ -9,6 +8,8 @@ from datetime import datetime
|
|||||||
import logging
|
import logging
|
||||||
from logging_config import setup_logging # logging 설정을 위한 import
|
from logging_config import setup_logging # logging 설정을 위한 import
|
||||||
import traceback
|
import traceback
|
||||||
|
import itertools
|
||||||
|
import copy
|
||||||
|
|
||||||
from script_utils import extract_and_format_scripts # 스크립트 추출 함수 import
|
from script_utils import extract_and_format_scripts # 스크립트 추출 함수 import
|
||||||
|
|
||||||
@@ -21,12 +22,12 @@ def read_json(file_path):
|
|||||||
|
|
||||||
# 요소 탐색 함수
|
# 요소 탐색 함수
|
||||||
def find_element(project_data, jsonpath_expr):
|
def find_element(project_data, jsonpath_expr):
|
||||||
jsonpath_expr = parse(jsonpath_expr)
|
"""
|
||||||
result = []
|
주어진 데이터(project_data)에서 jsonpath 표현식에 일치하는 모든 값들을 찾아
|
||||||
for match in jsonpath_expr.find(project_data):
|
리스트로 반환합니다.
|
||||||
value = match.value
|
"""
|
||||||
result.append(value)
|
parsed_expr = parse(jsonpath_expr)
|
||||||
return result
|
return [match.value for match in parsed_expr.find(project_data)]
|
||||||
|
|
||||||
# 요소 탐색 함수
|
# 요소 탐색 함수
|
||||||
def find_script_element(project_data, jsonpath_expr):
|
def find_script_element(project_data, jsonpath_expr):
|
||||||
@@ -40,13 +41,14 @@ def find_script_element(project_data, jsonpath_expr):
|
|||||||
|
|
||||||
# jsonpath_expr_list 로 넘어온 jsonpath들을 하나씩 parse 해주고 결과를 result 리스트로 반환
|
# jsonpath_expr_list 로 넘어온 jsonpath들을 하나씩 parse 해주고 결과를 result 리스트로 반환
|
||||||
def find_list_element(data, jsonpath_expr_list):
|
def find_list_element(data, jsonpath_expr_list):
|
||||||
result = []
|
"""
|
||||||
|
주어진 데이터(data)에서 여러 jsonpath 표현식들에 일치하는 값들을 찾아
|
||||||
for jsonpath_expr in jsonpath_expr_list:
|
결과를 리스트의 리스트 형태로 반환합니다.
|
||||||
jsonpath_expr = parse(jsonpath_expr)
|
"""
|
||||||
result.append([match.value for match in jsonpath_expr.find(data)])
|
return [
|
||||||
|
[match.value for match in parse(expr).find(data)]
|
||||||
return result
|
for expr in jsonpath_expr_list
|
||||||
|
]
|
||||||
|
|
||||||
# 스크립트 채점 진행 전 스크립트 블럭 순서가 when_run_button_click 1번째, when_clone_start 2번째 배열에 없으면
|
# 스크립트 채점 진행 전 스크립트 블럭 순서가 when_run_button_click 1번째, when_clone_start 2번째 배열에 없으면
|
||||||
# 리스트 순서 스왑해서 각각 0, 1번 순서로 배치될 수 있도록 함
|
# 리스트 순서 스왑해서 각각 0, 1번 순서로 배치될 수 있도록 함
|
||||||
@@ -113,10 +115,11 @@ def swap_script(origin):
|
|||||||
result.extend([block for _, block in key_press_blocks])
|
result.extend([block for _, block in key_press_blocks])
|
||||||
|
|
||||||
# 3. clone_start와 message_cast 블록 추가
|
# 3. clone_start와 message_cast 블록 추가
|
||||||
if clone_start_block:
|
|
||||||
result.append(clone_start_block)
|
|
||||||
if message_cast_block:
|
if message_cast_block:
|
||||||
result.extend(message_cast_block)
|
result.extend(message_cast_block)
|
||||||
|
if clone_start_block:
|
||||||
|
result.append(clone_start_block)
|
||||||
|
|
||||||
|
|
||||||
# 4. 나머지 블록 추가
|
# 4. 나머지 블록 추가
|
||||||
result.extend(other_blocks)
|
result.extend(other_blocks)
|
||||||
@@ -124,6 +127,49 @@ def swap_script(origin):
|
|||||||
# 결과가 비어있으면 원본 반환
|
# 결과가 비어있으면 원본 반환
|
||||||
return result if result else origin
|
return result if result else origin
|
||||||
|
|
||||||
|
def reorder_script_all_cases(script_json, block_event_order):
|
||||||
|
"""
|
||||||
|
script_json의 'type' 순서를 block_event_order 순서에 맞게 재정렬합니다.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
script_json (list[dict]): 각 요소가 {'type': '...', ...} 형태의 리스트
|
||||||
|
block_event_order (list[str]): 원하는 type 순서 예: ['when_run_button_click', 'when_message_cast']
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[dict]: block_event_order 순서대로 재정렬된 리스트
|
||||||
|
"""
|
||||||
|
# 타입별로 스크립트를 분류
|
||||||
|
type_map = {}
|
||||||
|
for s in script_json:
|
||||||
|
type_map.setdefault(s[0]["type"], []).append(s)
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
def backtrack(order_idx, used_counts, current):
|
||||||
|
# ✅ 모든 이벤트 순서를 처리했으면 결과에 추가
|
||||||
|
if order_idx == len(block_event_order):
|
||||||
|
results.append(copy.deepcopy(current))
|
||||||
|
return
|
||||||
|
|
||||||
|
event_type = block_event_order[order_idx]
|
||||||
|
available_scripts = type_map.get(event_type, [])
|
||||||
|
|
||||||
|
# 아직 사용하지 않은 script만 선택
|
||||||
|
for i, script in enumerate(available_scripts):
|
||||||
|
if used_counts[event_type][i]:
|
||||||
|
continue
|
||||||
|
used_counts[event_type][i] = True
|
||||||
|
current.append(script)
|
||||||
|
backtrack(order_idx + 1, used_counts, current)
|
||||||
|
current.pop()
|
||||||
|
used_counts[event_type][i] = False
|
||||||
|
|
||||||
|
# 사용 여부 초기화
|
||||||
|
used_counts = {t: [False] * len(lst) for t, lst in type_map.items()}
|
||||||
|
backtrack(0, used_counts, [])
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
def clean_string(text):
|
def clean_string(text):
|
||||||
"""문자열 끝의 . 또는 ! 제거"""
|
"""문자열 끝의 . 또는 ! 제거"""
|
||||||
if isinstance(text, str):
|
if isinstance(text, str):
|
||||||
@@ -141,12 +187,34 @@ def process_project(project_data, scoring_data):
|
|||||||
total_points = 0
|
total_points = 0
|
||||||
score_list = []
|
score_list = []
|
||||||
|
|
||||||
|
# - 시작하기 버튼을 클릭했을 때 : when_run_button_click
|
||||||
|
# - (특정) 신호를 받았을 때 : when_message_cast
|
||||||
|
# - 복제본이 생성 되었을 때 : when_clone_start
|
||||||
|
# - 장면이 시작 되었을 때 : when_scene_start
|
||||||
|
# - 오브젝트를 클릭 했을 때 : when_object_click
|
||||||
|
# 이벤트 블록이 존재하는지 여부 확인용 변수
|
||||||
|
target_event_type = {
|
||||||
|
"when_run_button_click",
|
||||||
|
"when_message_cast",
|
||||||
|
"when_clone_start",
|
||||||
|
"when_scene_start",
|
||||||
|
"when_object_click"
|
||||||
|
}
|
||||||
|
|
||||||
for question_key, question_info in scoring_data.items():
|
for question_key, question_info in scoring_data.items():
|
||||||
element_path = question_info.get('ele')
|
element_path = question_info.get('ele')
|
||||||
question_type = question_info.get('type')
|
question_type = question_info.get('type')
|
||||||
block_list = question_info.get('blocks')
|
block_list = question_info.get('blocks')
|
||||||
expected_answer = question_info.get('answer')
|
expected_answer = question_info.get('answer')
|
||||||
question_points = question_info.get('points')
|
question_points = question_info.get('point')
|
||||||
|
|
||||||
|
block_event_order = [] # 결과를 저장할 리스트 생성
|
||||||
|
|
||||||
|
if isinstance(block_list, list) and block_list:
|
||||||
|
for block in block_list:
|
||||||
|
answer = block.get("answer") # answer 키값을 안전하게 가져오기
|
||||||
|
if isinstance(answer, str) and answer in target_event_type:
|
||||||
|
block_event_order.append(answer) # 리스트에 추가
|
||||||
|
|
||||||
print(f"▶ Processing question: {question_key}")
|
print(f"▶ Processing question: {question_key}")
|
||||||
|
|
||||||
@@ -173,14 +241,16 @@ def process_project(project_data, scoring_data):
|
|||||||
elif question_type == "script":
|
elif question_type == "script":
|
||||||
script_raw = find_script_element(project_data, element_path)
|
script_raw = find_script_element(project_data, element_path)
|
||||||
script_json = json.loads(script_raw) if script_raw else None
|
script_json = json.loads(script_raw) if script_raw else None
|
||||||
script_data = swap_script(script_json) if script_json else None
|
|
||||||
|
# 스크립트 블록 순서 재정렬
|
||||||
|
script_data = reorder_script_all_cases(script_json, block_event_order) if script_json else None
|
||||||
|
|
||||||
block_index = 1
|
block_index = 1
|
||||||
for block in block_list:
|
for block in block_list:
|
||||||
block_type = block.get('type')
|
block_type = block.get('type')
|
||||||
block_path = block.get('ele')
|
block_path = block.get('ele')
|
||||||
block_answer = block.get('answer', None)
|
block_answer = block.get('answer', None)
|
||||||
block_points = block.get('points')
|
block_points = block.get('point')
|
||||||
|
|
||||||
if script_data is None:
|
if script_data is None:
|
||||||
print(f"{question_key}-{block_index}: Script Not Found")
|
print(f"{question_key}-{block_index}: Script Not Found")
|
||||||
@@ -188,34 +258,64 @@ def process_project(project_data, scoring_data):
|
|||||||
block_index += 1
|
block_index += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 블록 요소 검색
|
# 1. 현재 블록(문제)이 정답인지 판별하는 플래그
|
||||||
|
is_block_correct = False
|
||||||
|
|
||||||
|
# 2. 로깅을 위해 마지막으로 찾은 값을 저장할 변수
|
||||||
|
last_found_values = None
|
||||||
|
|
||||||
|
# 3. script_data가 단일 객체여도 처리 가능하도록 리스트로 통일
|
||||||
|
scripts_to_check = script_data if isinstance(script_data, list) else [script_data]
|
||||||
|
|
||||||
|
# 4. 여러 스크립트 뭉치를 순회하며 정답이 하나라도 있는지 확인
|
||||||
|
for single_script in scripts_to_check:
|
||||||
|
# 단일 스크립트 객체(single_script)에 대해 블록 요소 검색
|
||||||
if block_type == "list":
|
if block_type == "list":
|
||||||
block_elements = find_list_element(script_data, block_path)
|
block_elements = find_list_element(single_script, block_path)
|
||||||
else:
|
else:
|
||||||
block_elements = find_element(script_data, block_path)
|
block_elements = find_element(single_script, block_path)
|
||||||
|
|
||||||
# 결과값 정리
|
# 결과값 정리
|
||||||
if block_elements and isinstance(block_answer, list):
|
if block_elements and isinstance(block_answer, list):
|
||||||
found_values = [convert_to_str(x) for x in chain.from_iterable(block_elements)]
|
# 1. 비어있는 sublist를 ['None']으로 먼저 치환합니다.
|
||||||
|
# - sublist가 비어있지 않으면(if sublist) sublist를 그대로 사용하고,
|
||||||
|
# - 비어있으면 ['None']으로 대체합니다.
|
||||||
|
processed_elements = [sublist if sublist else ['None'] for sublist in block_elements]
|
||||||
|
found_values = [convert_to_str(x) for x in itertools.chain.from_iterable(processed_elements)]
|
||||||
else:
|
else:
|
||||||
found_values = convert_to_str(block_elements[0]) if block_elements else None
|
found_values = convert_to_str(block_elements[0]) if block_elements else None
|
||||||
|
|
||||||
|
# 실패 시 출력할 값을 위해 마지막으로 찾은 값을 저장
|
||||||
|
last_found_values = found_values
|
||||||
expected_str = convert_to_str(block_answer) if block_answer is not None else None
|
expected_str = convert_to_str(block_answer) if block_answer is not None else None
|
||||||
|
|
||||||
# 비교 및 점수 처리
|
# 정답 조건 확인
|
||||||
if block_elements:
|
if block_elements:
|
||||||
if block_answer is not None and expected_str != found_values:
|
# 5-1. 정답(block_answer)이 없고, 요소만 찾으면 되는 경우
|
||||||
print(f"{question_key}-{block_index}: ❌ {expected_str} != {found_values}")
|
if block_answer is None:
|
||||||
score_list.append(0)
|
is_block_correct = True
|
||||||
elif block_answer is not None and expected_str == found_values:
|
# 5-2. 정답이 있고, 찾은 값과 일치하는 경우
|
||||||
print(f"{question_key}-{block_index}: ✅ {expected_str} == {found_values}")
|
elif expected_str == found_values:
|
||||||
total_points += block_points
|
is_block_correct = True
|
||||||
score_list.append(block_points)
|
|
||||||
elif block_answer is None:
|
# 6. 정답을 찾았으면, 더 이상 다른 스크립트를 확인할 필요 없이 내부 반복문 탈출
|
||||||
total_points += block_points
|
if is_block_correct:
|
||||||
score_list.append(block_points)
|
break # for single_script in scripts_to_check: 루프를 중단
|
||||||
print(f"{question_key}-{block_index}: Element Exists")
|
|
||||||
|
# 7. 내부 반복문 종료 후, 플래그를 기반으로 최종 점수 처리
|
||||||
|
if is_block_correct:
|
||||||
|
# 정답을 맞힌 경우
|
||||||
|
if block_answer is not None:
|
||||||
|
print(f"{question_key}-{block_index}: ✅ {expected_str} == {last_found_values}")
|
||||||
else:
|
else:
|
||||||
|
print(f"{question_key}-{block_index}: Element Exists")
|
||||||
|
total_points += block_points
|
||||||
|
score_list.append(block_points)
|
||||||
|
else:
|
||||||
|
# 모든 스크립트를 확인했지만 정답이 없는 경우
|
||||||
|
if last_found_values is not None: # 요소는 찾았으나 값이 틀린 경우
|
||||||
|
print(f"{question_key}-{block_index}: ❌ {expected_str} != {last_found_values}")
|
||||||
|
else: # 요소를 전혀 찾지 못한 경우
|
||||||
print(f"{question_key}-{block_index}: No elements found for {block_path}")
|
print(f"{question_key}-{block_index}: No elements found for {block_path}")
|
||||||
score_list.append(0)
|
score_list.append(0)
|
||||||
|
|
||||||
@@ -234,8 +334,9 @@ def main():
|
|||||||
timestamp = datetime.now().strftime("%y%m%d")
|
timestamp = datetime.now().strftime("%y%m%d")
|
||||||
test_mode = False # 테스트 모드 설정
|
test_mode = False # 테스트 모드 설정
|
||||||
# test_mode = True # 테스트 모드 설정
|
# test_mode = True # 테스트 모드 설정
|
||||||
exam_round = "2509"
|
exam_round = "2510"
|
||||||
exam_names = ["CAT_3_A"] # 여러 시험명을 리스트로 설정
|
# exam_names = ["CAT_3_A"] # 여러 시험명을 리스트로 설정
|
||||||
|
exam_names = ["CAS_2_A"] # 여러 시험명을 리스트로 설정
|
||||||
excel_list = []
|
excel_list = []
|
||||||
|
|
||||||
for exam_name in exam_names:
|
for exam_name in exam_names:
|
||||||
|
|||||||
Reference in New Issue
Block a user