src/eric7/Plugins/CheckerPlugins/SyntaxChecker/tomlCheckSyntax.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 9107
8e9525a780ae
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2020 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the syntax check for TOML.
8 """
9
10 import queue
11 import multiprocessing
12
13
14 def initService():
15 """
16 Initialize the service and return the entry point.
17
18 @return the entry point for the background client
19 @rtype func
20 """
21 return tomlSyntaxCheck
22
23
24 def initBatchService():
25 """
26 Initialize the batch service and return the entry point.
27
28 @return the entry point for the background client
29 @rtype func
30 """
31 return tomlSyntaxBatchCheck
32
33
34 def normalizeCode(codestring):
35 """
36 Function to normalize the given code.
37
38 @param codestring code to be normalized
39 @type str
40 @return normalized code
41 @rtype str
42 """
43 codestring = codestring.replace("\r\n", "\n").replace("\r", "\n")
44
45 if codestring and codestring[-1] != '\n':
46 codestring += '\n'
47
48 return codestring
49
50
51 def tomlSyntaxCheck(file, codestring):
52 """
53 Function to check a TOML source file for syntax errors.
54
55 @param file source filename
56 @type str
57 @param codestring string containing the code to check
58 @type str
59 @return dictionary with the keys 'error' and 'warnings' which
60 hold a list containing details about the error/ warnings
61 (file name, line number, column, codestring (only at syntax
62 errors), the message, a list with arguments for the message)
63 @rtype dict
64 """
65 return __tomlSyntaxCheck(file, codestring)
66
67
68 def tomlSyntaxBatchCheck(argumentsList, send, fx, cancelled, maxProcesses=0):
69 """
70 Module function to check syntax for a batch of files.
71
72 @param argumentsList list of arguments tuples as given for tomlSyntaxCheck
73 @type list
74 @param send reference to send function
75 @type func
76 @param fx registered service name
77 @type str
78 @param cancelled reference to function checking for a cancellation
79 @type func
80 @param maxProcesses number of processes to be used
81 @type int
82 """
83 if maxProcesses == 0:
84 # determine based on CPU count
85 try:
86 NumberOfProcesses = multiprocessing.cpu_count()
87 if NumberOfProcesses >= 1:
88 NumberOfProcesses -= 1
89 except NotImplementedError:
90 NumberOfProcesses = 1
91 else:
92 NumberOfProcesses = maxProcesses
93
94 # Create queues
95 taskQueue = multiprocessing.Queue()
96 doneQueue = multiprocessing.Queue()
97
98 # Submit tasks (initially two time number of processes
99 initialTasks = 2 * NumberOfProcesses
100 for task in argumentsList[:initialTasks]:
101 taskQueue.put(task)
102
103 # Start worker processes
104 workers = [
105 multiprocessing.Process(
106 target=workerTask, args=(taskQueue, doneQueue)
107 ) for _ in range(NumberOfProcesses)
108 ]
109 for worker in workers:
110 worker.start()
111
112 # Get and send results
113 endIndex = len(argumentsList) - initialTasks
114 for i in range(len(argumentsList)):
115 resultSent = False
116 wasCancelled = False
117
118 while not resultSent:
119 try:
120 # get result (waiting max. 3 seconds and send it to frontend
121 filename, result = doneQueue.get()
122 send(fx, filename, result)
123 resultSent = True
124 except queue.Empty:
125 # ignore empty queue, just carry on
126 if cancelled():
127 wasCancelled = True
128 break
129
130 if wasCancelled or cancelled():
131 # just exit the loop ignoring the results of queued tasks
132 break
133
134 if i < endIndex:
135 taskQueue.put(argumentsList[i + initialTasks])
136
137 # Tell child processes to stop
138 for _ in range(NumberOfProcesses):
139 taskQueue.put('STOP')
140
141 for worker in workers:
142 worker.join()
143 worker.close()
144
145
146 def workerTask(inputQueue, outputQueue):
147 """
148 Module function acting as the parallel worker for the syntax check.
149
150 @param inputQueue input queue
151 @type multiprocessing.Queue
152 @param outputQueue output queue
153 @type multiprocessing.Queue
154 """
155 for filename, args in iter(inputQueue.get, 'STOP'):
156 source = args[0]
157 result = __tomlSyntaxCheck(filename, source)
158 outputQueue.put((filename, result))
159
160
161 def __tomlSyntaxCheck(file, codestring):
162 """
163 Function to check a TOML source file for syntax errors.
164
165 @param file source filename
166 @type str
167 @param codestring string containing the code to check
168 @type str
169 @return dictionary with the keys 'error' and 'warnings' which
170 hold a list containing details about the error/ warnings
171 (file name, line number, column, codestring (only at syntax
172 errors), the message, a list with arguments for the message)
173 @rtype dict
174 """
175 try:
176 import tomlkit
177 from tomlkit.exceptions import ParseError
178 except ImportError:
179 error = "tomlkit not available. Install it via the PyPI interface."
180 return [{'error': (file, 0, 0, '', error)}]
181
182 codestring = normalizeCode(codestring)
183
184 try:
185 tomlkit.parse(codestring)
186 except ParseError as exc:
187 line = exc.line
188 column = exc.col
189 error = str(exc).split(" at ", 1)[0].strip()
190 # get error message without location
191
192 cline = min(len(codestring.splitlines()), int(line)) - 1
193 code = codestring.splitlines()[cline]
194
195 return [{'error': (file, line, column, code, error)}]
196
197 return [{}]

eric ide

mercurial