44from fnmatch import fnmatch
55import json
66import logging
7- import os
7+ from pathlib import Path
88import shlex
99from subprocess import check_call , DEVNULL , CalledProcessError
1010import sys
1111
12- DEFAULT_SPEC_LOCATION = os .path .join (".." , "problem-specifications" )
12+ from data import Config , ExerciseInfo
13+ from test_exercises import check_assignment
14+
15+ DEFAULT_SPEC_LOCATION = Path ('spec' )
1316
1417logging .basicConfig (format = "%(levelname)s:%(message)s" )
1518logger = logging .getLogger ("generator" )
@@ -26,16 +29,6 @@ def __lt__(self, other):
2629 return self .value < other .value
2730
2831
29- with open ("config.json" ) as f :
30- config = json .load (f )
31-
32- exercises_dir = os .path .abspath ("exercises" )
33-
34-
35- def get_template_path (exercise ):
36- return os .path .join (exercises_dir , exercise , ".meta" , "template.j2" )
37-
38-
3932def exec_cmd (cmd ):
4033 try :
4134 args = shlex .split (cmd )
@@ -49,22 +42,20 @@ def exec_cmd(cmd):
4942 return False
5043
5144
52- def generate_template (exercise , spec_path ) :
53- script = os . path . abspath ( " bin/generate_tests.py" )
54- return exec_cmd (f'{ script } --verbose --spec-path "{ spec_path } " { exercise } ' )
45+ def generate_template (exercise : ExerciseInfo , spec_path : Path ) -> bool :
46+ script = Path ( ' bin/generate_tests.py' )
47+ return exec_cmd (f'{ script } --verbose --spec-path "{ spec_path } " { exercise . slug } ' )
5548
5649
57- def run_tests (exercise ):
58- script = os .path .abspath ("test/check-exercises.py" )
59- return exec_cmd (f"{ script } { exercise } " )
50+ def run_tests (exercise : ExerciseInfo ) -> bool :
51+ return check_assignment (exercise , quiet = True ) == 0
6052
6153
62- def get_status (exercise , spec_path ):
63- template_path = get_template_path (exercise )
64- if os .path .isfile (template_path ):
54+ def get_status (exercise : ExerciseInfo , spec_path : Path ):
55+ if exercise .template_path .is_file ():
6556 if generate_template (exercise , spec_path ):
6657 if run_tests (exercise ):
67- logging .info (f"{ exercise } : OK" )
58+ logging .info (f"{ exercise . slug } : OK" )
6859 return TemplateStatus .OK
6960 else :
7061 return TemplateStatus .TEST_FAILURE
@@ -84,6 +75,7 @@ def get_status(exercise, spec_path):
8475 "-p" ,
8576 "--spec-path" ,
8677 default = DEFAULT_SPEC_LOCATION ,
78+ type = Path ,
8779 help = (
8880 "path to clone of exercism/problem-specifications " "(default: %(default)s)"
8981 ),
@@ -96,10 +88,10 @@ def get_status(exercise, spec_path):
9688 elif opts .verbose >= 1 :
9789 logger .setLevel (logging .INFO )
9890
99- if not os . path . isdir ( opts .spec_path ):
91+ if not opts .spec_path . is_dir ( ):
10092 logger .error (f"{ opts .spec_path } is not a directory" )
10193 sys .exit (1 )
102- opts .spec_path = os . path . abspath ( opts .spec_path )
94+ opts .spec_path = opts .spec_path . absolute ( )
10395 logger .debug (f"problem-specifications path is { opts .spec_path } " )
10496
10597 result = True
@@ -108,20 +100,24 @@ def get_status(exercise, spec_path):
108100 TemplateStatus .INVALID : [],
109101 TemplateStatus .TEST_FAILURE : [],
110102 }
103+ config = Config .load ()
111104 for exercise in filter (
112- lambda e : fnmatch (e ["slug" ], opts .exercise_pattern ), config ["exercises" ]
105+ lambda e : fnmatch (e .slug , opts .exercise_pattern ),
106+ config .exercises .all ()
113107 ):
114- if exercise .get ('deprecated' , False ):
108+ if exercise .deprecated :
109+ continue
110+ if exercise .type == 'concept' :
111+ # Concept exercises are not generated
115112 continue
116- slug = exercise ["slug" ]
117- status = get_status (slug , opts .spec_path )
113+ status = get_status (exercise , opts .spec_path )
118114 if status == TemplateStatus .OK :
119- logger .info (f"{ slug } : { status .name } " )
115+ logger .info (f"{ exercise . slug } : { status .name } " )
120116 else :
121- buckets [status ].append (slug )
117+ buckets [status ].append (exercise . slug )
122118 result = False
123119 if opts .stop_on_failure :
124- logger .error (f"{ slug } : { status .name } " )
120+ logger .error (f"{ exercise . slug } : { status .name } " )
125121 break
126122
127123 if not opts .quiet and not opts .stop_on_failure :
0 commit comments