eric6/Plugins/CheckerPlugins/SyntaxChecker/yamlCheckSyntax.py

changeset 7335
07ed3d73bf58
child 7360
9190402e4505
equal deleted inserted replaced
7334:be378821131e 7335:07ed3d73bf58
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the syntax check for YAML.
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 yamlSyntaxCheck
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 yamlSyntaxBatchCheck
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 = codestring + '\n'
47
48 return codestring
49
50
51 def yamlSyntaxCheck(file, codestring):
52 """
53 Function to check a YAML 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 __yamlSyntaxCheck(file, codestring)
66
67
68 def yamlSyntaxBatchCheck(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 yamlSyntaxCheck
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 for _ in range(NumberOfProcesses):
105 multiprocessing.Process(
106 target=worker, args=(taskQueue, doneQueue)
107 ).start()
108
109 # Get and send results
110 endIndex = len(argumentsList) - initialTasks
111 for i in range(len(argumentsList)):
112 resultSent = False
113 wasCancelled = False
114
115 while not resultSent:
116 try:
117 # get result (waiting max. 3 seconds and send it to frontend
118 filename, result = doneQueue.get()
119 send(fx, filename, result)
120 resultSent = True
121 except queue.Empty:
122 # ignore empty queue, just carry on
123 if cancelled():
124 wasCancelled = True
125 break
126
127 if wasCancelled or cancelled():
128 # just exit the loop ignoring the results of queued tasks
129 break
130
131 if i < endIndex:
132 taskQueue.put(argumentsList[i + initialTasks])
133
134 # Tell child processes to stop
135 for _ in range(NumberOfProcesses):
136 taskQueue.put('STOP')
137
138
139 def worker(inputQueue, outputQueue):
140 """
141 Module function acting as the parallel worker for the syntax check.
142
143 @param inputQueue input queue
144 @type multiprocessing.Queue
145 @param outputQueue output queue
146 @type multiprocessing.Queue
147 """
148 for filename, args in iter(inputQueue.get, 'STOP'):
149 source = args[0]
150 result = __yamlSyntaxCheck(filename, source)
151 outputQueue.put((filename, result))
152
153
154 def __yamlSyntaxCheck(file, codestring):
155 """
156 Function to check a YAML source file for syntax errors.
157
158 @param file source filename
159 @type str
160 @param codestring string containing the code to check
161 @type str
162 @return dictionary with the keys 'error' and 'warnings' which
163 hold a list containing details about the error/ warnings
164 (file name, line number, column, codestring (only at syntax
165 errors), the message, a list with arguments for the message)
166 @rtype dict
167 """
168 try:
169 from yaml import safe_load_all, MarkedYAMLError
170 except ImportError:
171 error = "pyyaml not available. Install it via the PyPI interface."
172 return [{'error': (file, 0, 0, '', error)}]
173
174 codestring = normalizeCode(codestring)
175
176 try:
177 for _obj in safe_load_all(codestring):
178 # do nothing with it, just to get parse errors
179 pass
180 except MarkedYAMLError as exc:
181 if exc.problem_mark:
182 line = exc.problem_mark.line + 1
183 column = exc.problem_mark.column
184 else:
185 line, column = 0, 0
186 error = exc.problem
187 cline = min(len(codestring.splitlines()), int(line)) - 1
188 code = codestring.splitlines()[cline]
189 return [{'error': (file, line, column, code, error)}]
190
191 return [{}]

eric ide

mercurial