header.py

Tue, 25 Aug 2020 22:31:16 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 25 Aug 2020 22:31:16 +0300
changeset 101
745f2c3aec0a
parent 97
7b24ff111cb6
permissions
-rw-r--r--

added ability to get other header elements than just the first one

47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
1 import re
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
2 import linetypes
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
3 import datetime
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
4
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
5 class Header:
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
6 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
7 Result type of header processing, this contains all the header
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
8 information.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
9 '''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
10 def __init__(self):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
11 self.description = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
12 self.name = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
13 self.author = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
14 self.username = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
15 self.filetype = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
16 self.qualifiers = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
17 self.license = None
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
18 self.help = ''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
19 self.bfc = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
20 self.category = None
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
21 self.keywords = ''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
22 self.cmdline = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
23 self.history = []
101
745f2c3aec0a added ability to get other header elements than just the first one
Teemu Piippo <teemu@hecknology.net>
parents: 97
diff changeset
24 from collections import defaultdict
745f2c3aec0a added ability to get other header elements than just the first one
Teemu Piippo <teemu@hecknology.net>
parents: 97
diff changeset
25 self.occurrences = defaultdict(list)
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
26 @property
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
27 def valid(self):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
28 return True
69
a24c4490d9f2 added a check for keywords in non-parts
Teemu Piippo <teemu@hecknology.net>
parents: 67
diff changeset
29 @property
a24c4490d9f2 added a check for keywords in non-parts
Teemu Piippo <teemu@hecknology.net>
parents: 67
diff changeset
30 def effective_filetype(self):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
31 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
32 What's the effective file type? The "Unofficial_" prefix is
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
33 left out.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
34 '''
69
a24c4490d9f2 added a check for keywords in non-parts
Teemu Piippo <teemu@hecknology.net>
parents: 67
diff changeset
35 if self.filetype.startswith('Unofficial_'):
a24c4490d9f2 added a check for keywords in non-parts
Teemu Piippo <teemu@hecknology.net>
parents: 67
diff changeset
36 return self.filetype.rsplit('Unofficial_')[1]
a24c4490d9f2 added a check for keywords in non-parts
Teemu Piippo <teemu@hecknology.net>
parents: 67
diff changeset
37 else:
a24c4490d9f2 added a check for keywords in non-parts
Teemu Piippo <teemu@hecknology.net>
parents: 67
diff changeset
38 return self.filetype
79
eb93feb6d3a3 added a test for valid categories
Teemu Piippo <teemu@hecknology.net>
parents: 77
diff changeset
39 @property
eb93feb6d3a3 added a test for valid categories
Teemu Piippo <teemu@hecknology.net>
parents: 77
diff changeset
40 def effective_category(self):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
41 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
42 Returns the category of the part. Leading punctuation marks
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
43 are ignored.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
44 '''
79
eb93feb6d3a3 added a test for valid categories
Teemu Piippo <teemu@hecknology.net>
parents: 77
diff changeset
45 if self.category:
eb93feb6d3a3 added a test for valid categories
Teemu Piippo <teemu@hecknology.net>
parents: 77
diff changeset
46 return self.category
eb93feb6d3a3 added a test for valid categories
Teemu Piippo <teemu@hecknology.net>
parents: 77
diff changeset
47 else:
84
55d52e25267f fixed prefixed punctuations winding up in the effective categories of subparts
Teemu Piippo <teemu@hecknology.net>
parents: 79
diff changeset
48 import string
55d52e25267f fixed prefixed punctuations winding up in the effective categories of subparts
Teemu Piippo <teemu@hecknology.net>
parents: 79
diff changeset
49 category = self.description.split(' ', 1)[0]
55d52e25267f fixed prefixed punctuations winding up in the effective categories of subparts
Teemu Piippo <teemu@hecknology.net>
parents: 79
diff changeset
50 while category and category[0] in string.punctuation:
55d52e25267f fixed prefixed punctuations winding up in the effective categories of subparts
Teemu Piippo <teemu@hecknology.net>
parents: 79
diff changeset
51 category = category[1:]
55d52e25267f fixed prefixed punctuations winding up in the effective categories of subparts
Teemu Piippo <teemu@hecknology.net>
parents: 79
diff changeset
52 return category
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
53
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
54 class BadHeader:
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
55 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
56 If header processing fails this object is returned as the resulting
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
57 header instead. It contains the details of where the header could not
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
58 be understood and why.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
59 '''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
60 def __init__(self, index, reason):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
61 self.index = index
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
62 self.reason = reason
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
63 def __repr__(self):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
64 return str.format(
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
65 'header.BadHeader(index = {index!r}, reason = {reason!r})',
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
66 index = self.index,
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
67 reason = self.reason,
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
68 )
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
69 @property
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
70 def valid(self):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
71 return False
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
72
56
ed6d39c59e56 fixed BFC INVERTNEXT being interpreted as a header command
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
73 def is_invertnext(entry):
ed6d39c59e56 fixed BFC INVERTNEXT being interpreted as a header command
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
74 return isinstance(entry, linetypes.MetaCommand) \
ed6d39c59e56 fixed BFC INVERTNEXT being interpreted as a header command
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
75 and entry.text == "BFC INVERTNEXT"
ed6d39c59e56 fixed BFC INVERTNEXT being interpreted as a header command
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
76
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
77 def is_suitable_header_object(entry):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
78 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
79 Is the given object something that we can consider to be
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
80 part of the header?
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
81 '''
56
ed6d39c59e56 fixed BFC INVERTNEXT being interpreted as a header command
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
82 if is_invertnext(entry):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
83 # It's BFC INVERTNEXT, that's not a header command.
56
ed6d39c59e56 fixed BFC INVERTNEXT being interpreted as a header command
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
84 return False
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
85 # Check if it's one of the functional linetypes
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
86 return not any(
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
87 isinstance(entry, linetype)
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
88 for linetype in [
77
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
89 linetypes.SubfileReference,
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
90 linetypes.LineSegment,
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
91 linetypes.Triangle,
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
92 linetypes.Quadrilateral,
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
93 linetypes.ConditionalLine,
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
94 linetypes.Comment,
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
95 linetypes.Error,
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
96 ]
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
97 )
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
98
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
99 class HeaderError(Exception):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
100 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
101 An error raised during header parsing
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
102 '''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
103 def __init__(self, index, reason):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
104 self.index, self.reason = index, reason
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
105 def __repr__(self):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
106 return str.format(
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
107 'HeaderError({index!r}, {reason!r})',
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
108 index = self.index,
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
109 reason = self.reason,
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
110 )
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
111 def __str__(self):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
112 return reason
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
113
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
114 class HistoryEntry:
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
115 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
116 Represents a single !HISTORY entry
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
117 '''
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
118 def __init__(self, date, user, text):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
119 self.date, self.user, self.text = date, user, text
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
120 def __repr__(self):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
121 return str.format(
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
122 'HistoryEntry({date!r}, {user!r}, {text!r})',
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
123 date = self.date,
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
124 user = self.user,
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
125 text = self.text)
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
126
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
127 class HeaderParser:
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
128 def __init__(self):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
129 self.model_body = None
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
130 self.cursor = 0
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
131 self.problems = []
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
132 def parse(self, model_body):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
133 result = Header()
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
134 self.result = result
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
135 self.order = []
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
136 self.cursor = -1
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
137 self.model_body = model_body
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
138 self.skip_to_next()
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
139 result.description = self.current()
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
140 self.skip_to_next()
52
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
141 result.name = self.parse_pattern(r'^Name: (.+)$', 'name')[0]
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
142 self.skip_to_next()
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
143 # Parse author line
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
144 result.author, result.username = self.parse_pattern(r'^Author: (?:([^\[]+))?(?:\[([^\]]+)\])?', 'author')
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
145 if isinstance(result.author, str):
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
146 # clean leading spaces
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
147 result.author = str.strip(result.author)
76
c73432653fd9 fixed choking on 'Author: [PTAdmin]'-lines
Teemu Piippo <teemu@hecknology.net>
parents: 69
diff changeset
148 if not result.author and not result.username:
c73432653fd9 fixed choking on 'Author: [PTAdmin]'-lines
Teemu Piippo <teemu@hecknology.net>
parents: 69
diff changeset
149 self.parse_error('author line does not contain a name nor username')
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
150 # use more patterns to parse the rest of the header
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
151 for header_entry in self.get_more_header_stuff():
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
152 if self.try_to_match(
52
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
153 r'^!LDRAW_ORG ' \
49
a1f5c12fa45c fix LDRAW_ORG parsing
Teemu Piippo <teemu@hecknology.net>
parents: 48
diff changeset
154 r'((?:Unofficial_)?(?:' \
52
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
155 r'Part|' \
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
156 r'Subpart|' \
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
157 r'Primitive|' \
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
158 r'8_Primitive|' \
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
159 r'48_Primitive|' \
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
160 r'Shortcut' \
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
161 r'))\s?' \
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
162 r'(.*)$',
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
163 'part type'):
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
164 result.filetype = self.groups[0]
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
165 result.qualifiers = re.findall(r'(?:Physical_Colour|Alias|ORIGINAL|UPDATE \d\d\d\d-\d\d)', self.groups[1])
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
166 elif self.try_to_match(
52
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
167 r'^!LICENSE (.+)$',
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
168 'license'):
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
169 result.license = self.groups[0]
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
170 elif self.try_to_match(
52
cd2b4f3c1189 fix author parsing getting extra spaces in the name
Teemu Piippo <teemu@hecknology.net>
parents: 49
diff changeset
171 r'BFC (CERTIFY CW|CERTIFY CCW|NOCERTIFY)',
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
172 'bfc'):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
173 result.bfc = self.groups[0]
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
174 elif self.try_to_match(
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
175 r'!HISTORY (\d{4}-\d{2}-\d{2}) ([\[{][^\]}]+[\]}]) (.+)$',
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
176 'history'):
59
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
177 try:
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
178 time_object = datetime.datetime.strptime(
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
179 self.groups[0],
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
180 '%Y-%m-%d',
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
181 )
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
182 except ValueError:
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
183 self.parse_error("invalid ISO date in history")
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
184 result.history.append(HistoryEntry(
59
0f3e70a2bb4b report invalid ISO dates instead of crashing
Teemu Piippo <teemu@hecknology.net>
parents: 56
diff changeset
185 date = time_object.date(),
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
186 user = self.groups[1],
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
187 text = self.groups[2],
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
188 ))
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
189 elif self.try_to_match(
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
190 r'!HELP (.+)',
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
191 'help'):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
192 if result.help:
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
193 result.help += '\n'
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
194 result.help += self.groups[0]
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
195 elif self.try_to_match(
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
196 r'!CATEGORY (.+)',
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
197 'category'):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
198 result.category = self.groups[0]
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
199 elif self.try_to_match(
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
200 r'!KEYWORDS (.+)',
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
201 'keywords'):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
202 if result.keywords:
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
203 result.keywords += '\n'
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
204 result.keywords += self.groups[0]
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
205 elif self.try_to_match(
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
206 r'!CMDLINE (.+)',
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
207 'cmdline'):
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
208 result.cmdline = self.groups[0]
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
209 else:
77
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
210 self.cursor -= 1
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
211 break
67
afaa4d3bc3e5 complain if LDRAW_ORG line is missing
Teemu Piippo <teemu@hecknology.net>
parents: 60
diff changeset
212 if not result.filetype:
afaa4d3bc3e5 complain if LDRAW_ORG line is missing
Teemu Piippo <teemu@hecknology.net>
parents: 60
diff changeset
213 self.parse_error('LDRAW_ORG line is missing')
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
214 return {
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
215 'header': result,
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
216 'end-index': self.cursor + 1, # record where the header ended
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
217 }
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
218 def parse_error(self, message):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
219 raise HeaderError(index = self.cursor, reason = message)
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
220 def get_more_header_stuff(self):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
221 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
222 Iterates through the header and yields metacommand entries
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
223 one after the other.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
224 '''
77
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
225 self.cursor += 1
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
226 new_cursor = self.cursor
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
227 while new_cursor < len(self.model_body):
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
228 entry = self.model_body[new_cursor]
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
229 if not is_suitable_header_object(entry):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
230 # looks like the header ended
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
231 break
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
232 if isinstance(entry, linetypes.MetaCommand):
77
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
233 self.cursor = new_cursor
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
234 yield entry
77
d98502ae1f33 improved header extent scanning
Teemu Piippo <teemu@hecknology.net>
parents: 76
diff changeset
235 new_cursor += 1
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
236 def skip_to_next(self, *, spaces_expected = 0):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
237 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
238 Skip to the next header line.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
239 '''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
240 while True:
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
241 if self.cursor + 1 >= len(self.model_body):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
242 # wound up past the end of model
54
0c686d10eb49 added tests for moved-to files and scaling in flat dimensions
Teemu Piippo <teemu@hecknology.net>
parents: 52
diff changeset
243 self.parse_error('file does not have a proper header')
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
244 self.cursor += 1
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
245 entry = self.model_body[self.cursor]
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
246 if not is_suitable_header_object(entry):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
247 self.parse_error('header is incomplete')
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
248 if isinstance(entry, linetypes.MetaCommand):
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
249 return
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
250 def try_to_match(self, pattern, patterntype):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
251 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
252 Tries to parse the specified pattern and to store the groups in
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
253 self.groups. Returns whether or not this succeeded.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
254 '''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
255 try:
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
256 self.groups = self.parse_pattern(pattern, patterntype)
48
38b0919c1934 added some header tests
Teemu Piippo <teemu@hecknology.net>
parents: 47
diff changeset
257 return True
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
258 except:
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
259 return False
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
260 def current(self):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
261 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
262 Returns the text of the header line we're currently processing.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
263 '''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
264 entry = self.model_body[self.cursor]
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
265 assert isinstance(entry, linetypes.MetaCommand)
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
266 return entry.text
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
267 def parse_pattern(self, pattern, description):
97
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
268 '''
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
269 Matches the current header line against the specified pattern.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
270 If not, raises an exception. See try_to_match for a softer wrapper
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
271 that does not raise exceptions.
7b24ff111cb6 add comments
Teemu Piippo <teemu@hecknology.net>
parents: 84
diff changeset
272 '''
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
273 match = re.search(pattern, self.current())
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
274 if match:
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
275 self.order.append(description)
101
745f2c3aec0a added ability to get other header elements than just the first one
Teemu Piippo <teemu@hecknology.net>
parents: 97
diff changeset
276 list.append(self.result.occurrences[description], self.cursor)
47
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
277 return match.groups()
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
278 else:
4da025d0b283 added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
279 self.parse_error(str.format("couldn't parse {}", description))

mercurial