ldcheck.py

changeset 147
bec55b021ae7
parent 146
3555679d276b
parent 145
fde18c4d6784
child 149
7c01f9876b69
equal deleted inserted replaced
146:3555679d276b 147:bec55b021ae7
1 #!/usr/bin/env python3 1 #!/usr/bin/env python3
2 <<<<<<< /home/teemu/dev/ldcheck/ldcheck.py
2 import sys 3 import sys
3 if sys.version_info < (3, 4): 4 if sys.version_info < (3, 4):
5 =======
6 import argparse
7 from sys import version_info
8 if version_info < (3, 4):
9 >>>>>>> /tmp/ldcheck~other.ou_xbg_k.py
4 raise RuntimeError('Python 3.4 or newer required') 10 raise RuntimeError('Python 3.4 or newer required')
11 <<<<<<< /home/teemu/dev/ldcheck/ldcheck.py
5 from colours import load_colours 12 from colours import load_colours
13 =======
14
15 appname = 'ldcheck'
16 version = (1, 0, 9999)
17 version_string = str.join('.', map(str, version))
18
19 >>>>>>> /tmp/ldcheck~other.ou_xbg_k.py
6 from geometry import * 20 from geometry import *
7 from pathlib import Path 21 from pathlib import Path
8 import linetypes 22 import linetypes
9 import header 23 import header
10 import parse 24 import parse
11 25
26 <<<<<<< /home/teemu/dev/ldcheck/ldcheck.py
12 def check_library_paths(library_paths): 27 def check_library_paths(library_paths):
13 for library_path in library_paths: 28 for library_path in library_paths:
14 if not library_path.exists(): 29 if not library_path.exists():
15 raise RuntimeError(str.format( 30 raise RuntimeError(str.format(
16 'error: library path {} does not exist', 31 'error: library path {} does not exist',
35 if not ldconfig_ldr_paths: 50 if not ldconfig_ldr_paths:
36 raise RuntimeError('could not find any LDConfig.ldr') 51 raise RuntimeError('could not find any LDConfig.ldr')
37 for ldconfig_ldr_path in ldconfig_ldr_paths: 52 for ldconfig_ldr_path in ldconfig_ldr_paths:
38 with ldconfig_ldr_path.open() as ldconfig_ldr: 53 with ldconfig_ldr_path.open() as ldconfig_ldr:
39 load_colours(ldconfig_ldr) 54 load_colours(ldconfig_ldr)
40 55 =======
56 from os.path import realpath
57 script_directory = Path(realpath(__file__)).parent
58
59 def config_dirs():
60 import appdirs
61 appauthor = 'Teemu Piippo'
62 dirs = appdirs.AppDirs(appname, appauthor)
63 return {
64 'user': Path(dirs.user_config_dir),
65 'system': Path(dirs.site_config_dir),
66 }
67
68 def ldraw_dirs_from_config():
69 libraries = []
70 dirs = config_dirs()
71 for dirpath in [dirs['system'], dirs['user']]:
72 filename = dirpath / 'ldcheck.cfg'
73 from configobj import ConfigObj
74 config = ConfigObj(str(filename), encoding = 'UTF8')
75 if 'libraries' in config:
76 libraries = expand_paths(config['libraries'])
77 return libraries
78
79 def expand_paths(paths):
80 return [
81 Path(library).expanduser()
82 for library in paths
83 ]
84
85 class LDrawContext:
86 '''
87 Contains context-dependant LDraw information, like library directory
88 paths and the colour table.
89 '''
90 def __init__(self, libraries = None):
91 self._libraries = libraries
92 if not self._libraries:
93 self._libraries = ldraw_dirs_from_config()
94 self.ldconfig_colour_data = self.load_ldconfig_ldr()
95 self.check_library_paths()
96 @property
97 def libraries(self):
98 return self._libraries
99 @property
100 def colours(self):
101 return self.ldconfig_colour_data
102 def ldconfig_ldr_discovery(self):
103 for library_path in self.libraries:
104 yield from [
105 library_path / path
106 for path in ['LDConfig.ldr', 'ldconfig.ldr']
107 if (library_path / path).is_file()
108 ]
109 def load_ldconfig_ldr(self):
110 from colours import load_colours
111 for ldconfig_ldr_path in self.ldconfig_ldr_discovery():
112 with open(ldconfig_ldr_path) as ldconfig_ldr:
113 return load_colours(ldconfig_ldr)
114 def check_library_paths(self):
115 from sys import stderr
116 problems = False
117 have_paths = False
118 for library_path in self.libraries:
119 have_paths = True
120 if not library_path.exists():
121 problems = True
122 print(str.format(
123 'Library path {} does not exist',
124 library_path,
125 ), file = stderr)
126 elif not library_path.exists():
127 problems = True
128 print(str.format(
129 'Library path {} is not a directory',
130 library_path,
131 ), file = stderr)
132 if not have_paths:
133 raise RuntimeError('no LDraw library paths specified')
134 def is_ldconfig_colour(self, colour):
135 return colour.index in self.colours
136 def colour_name(self, colour):
137 if self.is_ldconfig_colour(colour):
138 return self.colours[self.index]['name']
139 else:
140 return str(colour)
141 def colour_face(self, colour):
142 if self.is_ldconfig_colour(colour):
143 return self.colours[self.index]['value']
144 elif colour.is_direct_colour:
145 return '#%06X' % (self.index & 0xffffff)
146 else:
147 return '#000000'
148 def is_valid_colour(self, colour):
149 return self.is_ldconfig_colour(colour) or colour.is_direct_colour
150 >>>>>>> /tmp/ldcheck~other.ou_xbg_k.py
151
152 <<<<<<< /home/teemu/dev/ldcheck/ldcheck.py
41 def parse_commandline_arguments(): 153 def parse_commandline_arguments():
42 import os 154 import os
43 rcpath = Path(os.path.expanduser('~/.config/ldcheckrc')) 155 rcpath = Path(os.path.expanduser('~/.config/ldcheckrc'))
44 if rcpath.exists(): 156 if rcpath.exists():
45 with rcpath.open() as file: 157 with rcpath.open() as file:
58 name = warning_type.name, 170 name = warning_type.name,
59 severity = warning_type.severity, 171 severity = warning_type.severity,
60 message = warning_type.placeholder_message(), 172 message = warning_type.placeholder_message(),
61 )) 173 ))
62 sys.exit(0) 174 sys.exit(0)
175 =======
176 class ListProblemsAction(argparse.Action):
177 def __init__(self, option_strings, dest, nargs = None, **kwargs):
178 super().__init__(option_strings, dest, nargs = 0, **kwargs)
179 def __call__(self, *args, **kwargs):
180 import testsuite
181 from sys import exit
182 from re import sub
183 test_suite = testsuite.load_tests()
184 for warning_type in testsuite.all_problem_types(test_suite):
185 print(str.format('{name}: {severity}: "{message}"',
186 name = warning_type.name,
187 severity = warning_type.severity,
188 message = warning_type.placeholder_message(),
189 ))
190 exit(0)
191
192 def format_report(report, model, test_suite, *, use_colors = True):
193 from testsuite import problem_text
194 messages = []
195 for problem in report['problems']:
196 text_colour = ''
197 if use_colors:
198 if problem.severity == 'hold':
199 text_colour = colorama.Fore.LIGHTRED_EX
200 elif problem.severity == 'warning':
201 text_colour = colorama.Fore.LIGHTBLUE_EX
202 ldraw_code = model.body[problem.body_index].textual_representation()
203 message = str.format(
204 '{text_colour}{model_name}:{line_number}: {problem_type}: {message}'
205 '{colour_reset}\n\t{ldraw_code}',
206 text_colour = text_colour,
207 model_name = model.name,
208 line_number = problem.line_number,
209 problem_type = problem.severity,
210 message = problem_text(problem, test_suite),
211 colour_reset = use_colors and colorama.Fore.RESET or '',
212 ldraw_code = ldraw_code,
213 )
214 messages.append(message)
215 return '\n'.join(messages)
216
217 if __name__ == '__main__':
218 from sys import argv, stderr, exit
219 >>>>>>> /tmp/ldcheck~other.ou_xbg_k.py
63 parser = argparse.ArgumentParser() 220 parser = argparse.ArgumentParser()
64 parser.add_argument('filename') 221 parser.add_argument('filename')
65 parser.add_argument('--list', 222 parser.add_argument('--list',
66 action = ListProblemTypesAction, 223 action = ListProblemTypesAction,
67 help = 'lists all possible problem types and exit', 224 help = 'lists all possible problem types and exit',
77 ) 234 )
78 parser.add_argument('--subfile', 235 parser.add_argument('--subfile',
79 action = 'store_true', 236 action = 'store_true',
80 help = 'finds a subfile by name and prints out information about it' 237 help = 'finds a subfile by name and prints out information about it'
81 ) 238 )
239 <<<<<<< /home/teemu/dev/ldcheck/ldcheck.py
82 parser.add_argument('-l', '--library', action = 'append') 240 parser.add_argument('-l', '--library', action = 'append')
83 arglist = rcargs + sys.argv[1:] 241 arglist = rcargs + sys.argv[1:]
84 return parser.parse_args(arglist) 242 return parser.parse_args(arglist)
85 243
86 def main(): 244 def main():
95 # directory 253 # directory
96 import os 254 import os
97 libraries = [Path(os.path.expanduser(library)) for library in args.library] 255 libraries = [Path(os.path.expanduser(library)) for library in args.library]
98 check_library_paths(libraries) 256 check_library_paths(libraries)
99 load_ldconfig(libraries) 257 load_ldconfig(libraries)
258 =======
259 parser.add_argument('--color',
260 action = 'store_true',
261 help = 'use colors'
262 )
263 parser.add_argument('-d', '--ldraw-dir',
264 nargs = '+',
265 help = 'specify LDraw directory path(s)',
266 )
267 parser.add_argument('-v', '--version',
268 action = 'version',
269 version = str.format('{appname} {version}',
270 appname = appname,
271 version = version_string,
272 ),
273 )
274 args = parser.parse_args()
275 libraries = ldraw_dirs_from_config()
276 if args.ldraw_dir:
277 libraries = expand_paths(args.ldraw_dir)
278 try:
279 context = LDrawContext(libraries)
280 except RuntimeError as error:
281 print('error:', str(error), file = stderr)
282 exit(1)
283 if args.color:
284 try:
285 import colorama
286 colorama.init()
287 except ImportError:
288 print('Use of --color requires the colorama module, disabling colours', file = stderr)
289 args.color = False
290 >>>>>>> /tmp/ldcheck~other.ou_xbg_k.py
100 if args.subfile: 291 if args.subfile:
101 # Subfile debug mode: searches for the specified subfile from the LDraw 292 # Subfile debug mode: searches for the specified subfile from the LDraw
102 # libraries, opens it as if it was referenced by something and prints 293 # libraries, opens it as if it was referenced by something and prints
103 # out all information that is calculated from this subfile. 294 # out all information that is calculated from this subfile.
104 import filecache 295 import filecache
296 <<<<<<< /home/teemu/dev/ldcheck/ldcheck.py
105 cache = filecache.SubfileCache(ldraw_directories = libraries) 297 cache = filecache.SubfileCache(ldraw_directories = libraries)
298 =======
299 cache = filecache.SubfileCache(context = context)
300 >>>>>>> /tmp/ldcheck~other.ou_xbg_k.py
106 subfile = cache.prepare_file(args.filename) 301 subfile = cache.prepare_file(args.filename)
107 if not subfile.valid: 302 if not subfile.valid:
108 print(subfile.problem) 303 print(subfile.problem)
109 else: 304 else:
110 print('Flat dimensions:', repr(subfile.flatness)) 305 print('Flat dimensions:', repr(subfile.flatness))
111 print('Description:', repr(subfile.description)) 306 print('Description:', repr(subfile.description))
112 print('Contains studs:', repr(subfile.has_studs)) 307 print('Contains studs:', repr(subfile.has_studs))
113 else: 308 else:
309 <<<<<<< /home/teemu/dev/ldcheck/ldcheck.py
114 with open(args.filename, 'rb') as file: 310 with open(args.filename, 'rb') as file:
115 from os.path import basename 311 from os.path import basename
116 model = parse.read_ldraw( 312 model = parse.read_ldraw(
117 file, 313 file,
118 name = basename(args.filename), 314 name = basename(args.filename),
152 main() 348 main()
153 except RuntimeError as e: 349 except RuntimeError as e:
154 import sys 350 import sys
155 print('error:', str(e), file = sys.stderr) 351 print('error:', str(e), file = sys.stderr)
156 sys.exit(1) 352 sys.exit(1)
353 =======
354 try:
355 with open(args.filename, 'rb') as file:
356 from os.path import basename
357 model = parse.read_ldraw(
358 file,
359 name = basename(args.filename),
360 context = context)
361 if args.dump:
362 print('header: ' + type(model.header).__name__)
363 for key in sorted(dir(model.header)):
364 if not key.startswith('__'):
365 print('\t' + key + ': ' + repr(getattr(model.header, key)))
366 for i, entry in enumerate(model.body):
367 if model.header.valid and i == model.header_size:
368 print('--------- End of header')
369 print(entry)
370 elif args.rebuild:
371 for entry in model.body:
372 print(entry.textual_representation(), end = '\r\n')
373 else:
374 from testsuite import load_tests, check_model
375 test_suite = load_tests()
376 report = check_model(model, test_suite)
377 print(format_report(
378 report,
379 model,
380 test_suite,
381 use_colors = args.color
382 ))
383 except FileNotFoundError:
384 print(str.format(
385 'no such file: {filename!r}',
386 filename = args.filename
387 ), file = stderr)
388 exit(1)
389 >>>>>>> /tmp/ldcheck~other.ou_xbg_k.py

mercurial