44 ): |
44 ): |
45 """ |
45 """ |
46 Module function to raise a SyntaxError for a SyntaxWarning. |
46 Module function to raise a SyntaxError for a SyntaxWarning. |
47 |
47 |
48 @param message warning object |
48 @param message warning object |
|
49 @type Class |
49 @param category type object of the warning |
50 @param category type object of the warning |
50 @param filename name of the file causing the warning (string) |
51 @type SyntaxWarning |
51 @param lineno line number causing the warning (integer) |
52 @param filename name of the file causing the warning |
|
53 @type str |
|
54 @param lineno line number causing the warning |
|
55 @type int |
52 @param file file to write the warning message to (ignored) |
56 @param file file to write the warning message to (ignored) |
|
57 @type file |
53 @param line line causing the warning (ignored) |
58 @param line line causing the warning (ignored) |
54 @raise err exception of type SyntaxError |
59 @type int |
|
60 @exception err exception of type SyntaxError |
55 """ |
61 """ |
56 if category is SyntaxWarning: |
62 if category is SyntaxWarning: |
57 err = SyntaxError(str(message)) |
63 err = SyntaxError(str(message)) |
58 err.filename = filename |
64 err.filename = filename |
59 err.lineno = lineno |
65 err.lineno = lineno |
170 |
176 |
171 def __init__(self, coding): |
177 def __init__(self, coding): |
172 """ |
178 """ |
173 Constructor |
179 Constructor |
174 |
180 |
175 @param coding coding to include in the message (string) |
181 @param coding coding to include in the message |
|
182 @type str |
176 """ |
183 """ |
177 self.errorMessage = QCoreApplication.translate( |
184 self.errorMessage = QCoreApplication.translate( |
178 "CodingError", "The coding '{0}' is wrong for the given text." |
185 "CodingError", "The coding '{0}' is wrong for the given text." |
179 ).format(coding) |
186 ).format(coding) |
180 |
187 |
181 def __repr__(self): |
188 def __repr__(self): |
182 """ |
189 """ |
183 Special method returning a representation of the exception. |
190 Special method returning a representation of the exception. |
184 |
191 |
185 @return string representing the error message |
192 @return string representing the error message |
|
193 @rtype str |
186 """ |
194 """ |
187 return str(self.errorMessage) |
195 return str(self.errorMessage) |
188 |
196 |
189 def __str__(self): |
197 def __str__(self): |
190 """ |
198 """ |
191 Special method returning a string representation of the exception. |
199 Special method returning a string representation of the exception. |
192 |
200 |
193 @return string representing the error message |
201 @return string representing the error message |
|
202 @rtype str |
194 """ |
203 """ |
195 return str(self.errorMessage) |
204 return str(self.errorMessage) |
196 |
205 |
197 |
206 |
198 def get_codingBytes(text): |
207 def get_codingBytes(text): |
199 """ |
208 """ |
200 Function to get the coding of a bytes text. |
209 Function to get the coding of a bytes text. |
201 |
210 |
202 @param text bytes text to inspect (bytes) |
211 @param text bytes text to inspect |
|
212 @type bytes |
203 @return coding string |
213 @return coding string |
|
214 @rtype str |
204 """ |
215 """ |
205 lines = text.splitlines() |
216 lines = text.splitlines() |
206 for coding in codingBytes_regexps: |
217 for coding in codingBytes_regexps: |
207 coding_re = coding[1] |
218 coding_re = coding[1] |
208 head = lines[: coding[0]] |
219 head = lines[: coding[0]] |
215 |
226 |
216 def get_coding(text): |
227 def get_coding(text): |
217 """ |
228 """ |
218 Function to get the coding of a text. |
229 Function to get the coding of a text. |
219 |
230 |
220 @param text text to inspect (string) |
231 @param text text to inspect |
|
232 @type str |
221 @return coding string |
233 @return coding string |
|
234 @rtype str |
222 """ |
235 """ |
223 lines = text.splitlines() |
236 lines = text.splitlines() |
224 for coding in coding_regexps: |
237 for coding in coding_regexps: |
225 coding_re = coding[1] |
238 coding_re = coding[1] |
226 head = lines[: coding[0]] |
239 head = lines[: coding[0]] |
233 |
246 |
234 def readEncodedFile(filename): |
247 def readEncodedFile(filename): |
235 """ |
248 """ |
236 Function to read a file and decode its contents into proper text. |
249 Function to read a file and decode its contents into proper text. |
237 |
250 |
238 @param filename name of the file to read (string) |
251 @param filename name of the file to read |
239 @return tuple of decoded text and encoding (string, string) |
252 @type str |
|
253 @return tuple of decoded text and encoding |
|
254 @rtype tuple of (str, str) |
240 """ |
255 """ |
241 with open(filename, "rb") as f: |
256 with open(filename, "rb") as f: |
242 text = f.read() |
257 text = f.read() |
243 return decode(text) |
258 return decode(text) |
244 |
259 |
246 def readEncodedFileWithHash(filename): |
261 def readEncodedFileWithHash(filename): |
247 """ |
262 """ |
248 Function to read a file, calculate a hash value and decode its contents |
263 Function to read a file, calculate a hash value and decode its contents |
249 into proper text. |
264 into proper text. |
250 |
265 |
251 @param filename name of the file to read (string) |
266 @param filename name of the file to read |
252 @return tuple of decoded text, encoding and hash value (string, string, |
267 @type str |
253 string) |
268 @return tuple of decoded text, encoding and hash value |
|
269 @rtype tuple of (str, str, str) |
254 """ |
270 """ |
255 with open(filename, "rb") as f: |
271 with open(filename, "rb") as f: |
256 text = f.read() |
272 text = f.read() |
257 hashStr = str( |
273 hashStr = str( |
258 QCryptographicHash.hash( |
274 QCryptographicHash.hash( |
265 |
281 |
266 def decode(text): |
282 def decode(text): |
267 """ |
283 """ |
268 Function to decode some byte text into a string. |
284 Function to decode some byte text into a string. |
269 |
285 |
270 @param text byte text to decode (bytes) |
286 @param text byte text to decode |
271 @return tuple of decoded text and encoding (string, string) |
287 @type bytes |
|
288 @return tuple of decoded text and encoding |
|
289 @rtype tuple of (str, str) |
272 """ |
290 """ |
273 with contextlib.suppress(UnicodeError, LookupError): |
291 with contextlib.suppress(UnicodeError, LookupError): |
274 if text.startswith(BOM_UTF8): |
292 if text.startswith(BOM_UTF8): |
275 # UTF-8 with BOM |
293 # UTF-8 with BOM |
276 return str(text[len(BOM_UTF8) :], "utf-8"), "utf-8-bom" |
294 return str(text[len(BOM_UTF8) :], "utf-8"), "utf-8-bom" |
322 |
340 |
323 def readEncodedFileWithEncoding(filename, encoding): |
341 def readEncodedFileWithEncoding(filename, encoding): |
324 """ |
342 """ |
325 Function to read a file and decode its contents into proper text. |
343 Function to read a file and decode its contents into proper text. |
326 |
344 |
327 @param filename name of the file to read (string) |
345 @param filename name of the file to read |
328 @param encoding encoding to be used to read the file (string) |
346 @type str |
329 @return tuple of decoded text and encoding (string, string) |
347 @param encoding encoding to be used to read the file |
|
348 @type str |
|
349 @return tuple of decoded text and encoding |
|
350 @rtype tuple of (str, str) |
330 """ |
351 """ |
331 with open(filename, "rb") as f: |
352 with open(filename, "rb") as f: |
332 text = f.read() |
353 text = f.read() |
333 if encoding: |
354 if encoding: |
334 with contextlib.suppress(UnicodeError, LookupError): |
355 with contextlib.suppress(UnicodeError, LookupError): |
436 |
457 |
437 def decodeString(text): |
458 def decodeString(text): |
438 """ |
459 """ |
439 Function to decode a string containing Unicode encoded characters. |
460 Function to decode a string containing Unicode encoded characters. |
440 |
461 |
441 @param text text containing encoded chars (string) |
462 @param text text containing encoded chars |
442 @return decoded text (string) |
463 @type str |
|
464 @return decoded text |
|
465 @rtype str |
443 """ |
466 """ |
444 buf = b"" |
467 buf = b"" |
445 index = 0 |
468 index = 0 |
446 while index < len(text): |
469 while index < len(text): |
447 if text[index] == "\\": |
470 if text[index] == "\\": |
457 |
480 |
458 def decodeBytes(buffer): |
481 def decodeBytes(buffer): |
459 """ |
482 """ |
460 Function to decode some byte text into a string. |
483 Function to decode some byte text into a string. |
461 |
484 |
462 @param buffer byte buffer to decode (bytes) |
485 @param buffer byte buffer to decode |
463 @return decoded text (string) |
486 @type bytes |
|
487 @return decoded text |
|
488 @rtype str |
464 """ |
489 """ |
465 # try UTF with BOM |
490 # try UTF with BOM |
466 with contextlib.suppress(UnicodeError, LookupError): |
491 with contextlib.suppress(UnicodeError, LookupError): |
467 if buffer.startswith(BOM_UTF8): |
492 if buffer.startswith(BOM_UTF8): |
468 # UTF-8 with BOM |
493 # UTF-8 with BOM |
494 |
519 |
495 def readStringFromStream(stream): |
520 def readStringFromStream(stream): |
496 """ |
521 """ |
497 Module function to read a string from the given stream. |
522 Module function to read a string from the given stream. |
498 |
523 |
499 @param stream data stream opened for reading (QDataStream) |
524 @param stream data stream opened for reading |
500 @return string read from the stream (string) |
525 @type QDataStream |
|
526 @return string read from the stream |
|
527 @rtype str |
501 """ |
528 """ |
502 data = stream.readString() |
529 data = stream.readString() |
503 if data is None: |
530 if data is None: |
504 data = b"" |
531 data = b"" |
505 return data.decode("utf-8") |
532 return data.decode("utf-8") |
507 |
534 |
508 def normalizeCode(codestring): |
535 def normalizeCode(codestring): |
509 """ |
536 """ |
510 Function to normalize the given code. |
537 Function to normalize the given code. |
511 |
538 |
512 @param codestring code to be normalized (string) |
539 @param codestring code to be normalized |
513 @return normalized code (string) |
540 @type str |
|
541 @return normalized code |
|
542 @rtype str |
514 """ |
543 """ |
515 codestring = codestring.replace("\r\n", "\n").replace("\r", "\n") |
544 codestring = codestring.replace("\r\n", "\n").replace("\r", "\n") |
516 |
545 |
517 if codestring and codestring[-1] != "\n": |
546 if codestring and codestring[-1] != "\n": |
518 codestring += "\n" |
547 codestring += "\n" |
534 def escape_entities(m, escmap=_escape_map): |
563 def escape_entities(m, escmap=_escape_map): |
535 """ |
564 """ |
536 Function to encode html entities. |
565 Function to encode html entities. |
537 |
566 |
538 @param m the match object |
567 @param m the match object |
|
568 @type re.Match |
539 @param escmap the map of entities to encode |
569 @param escmap the map of entities to encode |
540 @return the converted text (string) |
570 @type dict |
|
571 @return the converted text |
|
572 @rtype str |
541 """ |
573 """ |
542 char = m.group() |
574 char = m.group() |
543 text = escmap.get(char) |
575 text = escmap.get(char) |
544 if text is None: |
576 if text is None: |
545 text = "&#{0:d};".format(ord(char)) |
577 text = "&#{0:d};".format(ord(char)) |
548 |
580 |
549 def html_encode(text, pattern=_escape): |
581 def html_encode(text, pattern=_escape): |
550 """ |
582 """ |
551 Function to correctly encode a text for html. |
583 Function to correctly encode a text for html. |
552 |
584 |
553 @param text text to be encoded (string) |
585 @param text text to be encoded |
554 @param pattern search pattern for text to be encoded (string) |
586 @type str |
555 @return the encoded text (string) |
587 @param pattern search pattern for text to be encoded |
|
588 @type str |
|
589 @return the encoded text |
|
590 @rtype str |
556 """ |
591 """ |
557 if not text: |
592 if not text: |
558 return "" |
593 return "" |
559 text = pattern.sub(escape_entities, text) |
594 text = pattern.sub(escape_entities, text) |
560 return text |
595 return text |
566 def escape_uentities(m): |
601 def escape_uentities(m): |
567 """ |
602 """ |
568 Function to encode html entities. |
603 Function to encode html entities. |
569 |
604 |
570 @param m the match object |
605 @param m the match object |
571 @return the converted text (string) |
606 @type re.Match |
|
607 @return the converted text |
|
608 @rtype str |
572 """ |
609 """ |
573 char = m.group() |
610 char = m.group() |
574 text = "&#{0:d};".format(ord(char)) |
611 text = "&#{0:d};".format(ord(char)) |
575 return text |
612 return text |
576 |
613 |
577 |
614 |
578 def html_uencode(text, pattern=_uescape): |
615 def html_uencode(text, pattern=_uescape): |
579 """ |
616 """ |
580 Function to correctly encode a unicode text for html. |
617 Function to correctly encode a unicode text for html. |
581 |
618 |
582 @param text text to be encoded (string) |
619 @param text text to be encoded |
583 @param pattern search pattern for text to be encoded (string) |
620 @type str |
584 @return the encoded text (string) |
621 @param pattern search pattern for text to be encoded |
|
622 @type str |
|
623 @return the encoded text |
|
624 @rtype str |
585 """ |
625 """ |
586 if not text: |
626 if not text: |
587 return "" |
627 return "" |
588 text = pattern.sub(escape_uentities, text) |
628 text = pattern.sub(escape_uentities, text) |
589 return text |
629 return text |
595 def unescape_uentities(m): |
635 def unescape_uentities(m): |
596 """ |
636 """ |
597 Function to decode html entities. |
637 Function to decode html entities. |
598 |
638 |
599 @param m the match object |
639 @param m the match object |
600 @return the converted text (string) |
640 @type re.Match |
|
641 @return the converted text |
|
642 @rtype str |
601 """ |
643 """ |
602 char = m.group() |
644 char = m.group() |
603 ordinal = int(char[2:-1]) |
645 ordinal = int(char[2:-1]) |
604 return chr(ordinal) |
646 return chr(ordinal) |
605 |
647 |
606 |
648 |
607 def html_udecode(text, pattern=_uunescape): |
649 def html_udecode(text, pattern=_uunescape): |
608 """ |
650 """ |
609 Function to correctly decode a html text to a unicode text. |
651 Function to correctly decode a html text to a unicode text. |
610 |
652 |
611 @param text text to be decoded (string) |
653 @param text text to be decoded |
612 @param pattern search pattern for text to be decoded (string) |
654 @type str |
613 @return the decoded text (string) |
655 @param pattern search pattern for text to be decoded |
|
656 @type str |
|
657 @return the decoded text |
|
658 @rtype str |
614 """ |
659 """ |
615 if not text: |
660 if not text: |
616 return "" |
661 return "" |
617 text = pattern.sub(unescape_uentities, text) |
662 text = pattern.sub(unescape_uentities, text) |
618 return text |
663 return text |
620 |
665 |
621 def convertLineEnds(text, eol): |
666 def convertLineEnds(text, eol): |
622 """ |
667 """ |
623 Function to convert the end of line characters. |
668 Function to convert the end of line characters. |
624 |
669 |
625 @param text text to be converted (string) |
670 @param text text to be converted |
626 @param eol new eol setting (string) |
671 @type str |
627 @return text with converted eols (string) |
672 @param eol new eol setting |
|
673 @type str |
|
674 @return text with converted eols |
|
675 @rtype str |
628 """ |
676 """ |
629 if eol == "\r\n": |
677 if eol == "\r\n": |
630 regexp = re.compile(r"""(\r(?!\n)|(?<!\r)\n)""") |
678 regexp = re.compile(r"""(\r(?!\n)|(?<!\r)\n)""") |
631 return regexp.sub("\r\n", text) |
679 return regexp.sub("\r\n", text) |
632 elif eol == "\n": |
680 elif eol == "\n": |
641 |
689 |
642 def linesep(): |
690 def linesep(): |
643 """ |
691 """ |
644 Function to return the line separator used by the editor. |
692 Function to return the line separator used by the editor. |
645 |
693 |
646 @return line separator used by the editor (string) |
694 @return line separator used by the editor |
|
695 @rtype str |
647 """ |
696 """ |
648 eolMode = Preferences.getEditor("EOLMode") |
697 eolMode = Preferences.getEditor("EOLMode") |
649 if eolMode == QsciScintilla.EolMode.EolUnix: |
698 if eolMode == QsciScintilla.EolMode.EolUnix: |
650 return "\n" |
699 return "\n" |
651 elif eolMode == QsciScintilla.EolMode.EolMac: |
700 elif eolMode == QsciScintilla.EolMode.EolMac: |
664 is assumed to be a string. If a key does not contain a '=' |
713 is assumed to be a string. If a key does not contain a '=' |
665 character, it is assumed to be a boolean flag. Flags are expected |
714 character, it is assumed to be a boolean flag. Flags are expected |
666 at the very end of a file. The search is ended, if a line without |
715 at the very end of a file. The search is ended, if a line without |
667 the 'eflag:' marker is found. |
716 the 'eflag:' marker is found. |
668 |
717 |
669 @param text text to be scanned (string) |
718 @param text text to be scanned |
|
719 @type str |
670 @return dictionary of string, boolean, complex, float and int |
720 @return dictionary of string, boolean, complex, float and int |
|
721 @rtype dict |
671 """ |
722 """ |
672 flags = {} |
723 flags = {} |
673 lines = text.rstrip().splitlines() if isinstance(text, str) else text |
724 lines = text.rstrip().splitlines() if isinstance(text, str) else text |
674 for line in reversed(lines): |
725 for line in reversed(lines): |
675 try: |
726 try: |
711 |
762 |
712 def extractFlagsFromFile(filename): |
763 def extractFlagsFromFile(filename): |
713 """ |
764 """ |
714 Function to extract eric specific flags out of the given file. |
765 Function to extract eric specific flags out of the given file. |
715 |
766 |
716 @param filename name of the file to be scanned (string) |
767 @param filename name of the file to be scanned |
|
768 @type str |
717 @return dictionary of string, boolean, complex, float and int |
769 @return dictionary of string, boolean, complex, float and int |
|
770 @rtype dict |
718 """ |
771 """ |
719 try: |
772 try: |
720 source, encoding = readEncodedFile(filename) |
773 source, encoding = readEncodedFile(filename) |
721 except (OSError, UnicodeError): |
774 except (OSError, UnicodeError): |
722 return {} |
775 return {} |
727 def extractLineFlags(line, startComment="#", endComment="", flagsLine=False): |
780 def extractLineFlags(line, startComment="#", endComment="", flagsLine=False): |
728 """ |
781 """ |
729 Function to extract flags starting and ending with '__' from a line |
782 Function to extract flags starting and ending with '__' from a line |
730 comment. |
783 comment. |
731 |
784 |
732 @param line line to extract flags from (string) |
785 @param line line to extract flags from |
733 @param startComment string identifying the start of the comment (string) |
786 @type str |
734 @param endComment string identifying the end of a comment (string) |
787 @param startComment string identifying the start of the comment |
735 @param flagsLine flag indicating to check for a flags only line (bool) |
788 @type str |
736 @return list containing the extracted flags (list of strings) |
789 @param endComment string identifying the end of a comment |
|
790 @type str |
|
791 @param flagsLine flag indicating to check for a flags only line |
|
792 @type bool |
|
793 @return list containing the extracted flags |
|
794 @rtype list of str |
737 """ |
795 """ |
738 flags = [] |
796 flags = [] |
739 |
797 |
740 if not flagsLine or (flagsLine and line.strip().startswith(startComment)): |
798 if not flagsLine or (flagsLine and line.strip().startswith(startComment)): |
741 pos = line.rfind(startComment) |
799 pos = line.rfind(startComment) |
985 |
1043 |
986 def getPercentReplacementHelp(): |
1044 def getPercentReplacementHelp(): |
987 """ |
1045 """ |
988 Function to get the help text for the supported %-codes. |
1046 Function to get the help text for the supported %-codes. |
989 |
1047 |
990 @returns help text (string) |
1048 @return help text |
|
1049 @rtype str |
991 """ |
1050 """ |
992 return QCoreApplication.translate( |
1051 return QCoreApplication.translate( |
993 "Utilities", |
1052 "Utilities", |
994 """<p>You may use %-codes as placeholders in the string.""" |
1053 """<p>You may use %-codes as placeholders in the string.""" |
995 """ Supported codes are:""" |
1054 """ Supported codes are:""" |
1025 match = rx.search(txt) |
1084 match = rx.search(txt) |
1026 if match is None: |
1085 if match is None: |
1027 return -1 |
1086 return -1 |
1028 else: |
1087 else: |
1029 return match.start() |
1088 return match.start() |
|
1089 |
|
1090 |
|
1091 def unslash(txt): |
|
1092 """ |
|
1093 Function to convert a string containing escape codes to an escaped string. |
|
1094 |
|
1095 @param txt string to be converted |
|
1096 @type str |
|
1097 @return converted string containing escape codes |
|
1098 @rtype str |
|
1099 """ |
|
1100 s = [] |
|
1101 index = 0 |
|
1102 while index < len(txt): |
|
1103 c = txt[index] |
|
1104 if c == "\\" and index + 1 < len(txt): |
|
1105 index += 1 |
|
1106 c = txt[index] |
|
1107 if c == "a": |
|
1108 o = "\a" |
|
1109 elif c == "b": |
|
1110 o = "\b" |
|
1111 elif c == "f": |
|
1112 o = "\f" |
|
1113 elif c == "n": |
|
1114 o = "\n" |
|
1115 elif c == "r": |
|
1116 o = "\r" |
|
1117 elif c == "t": |
|
1118 o = "\t" |
|
1119 elif c == "v": |
|
1120 o = "\v" |
|
1121 elif c in "01234567": |
|
1122 # octal |
|
1123 oc = c |
|
1124 if index + 1 < len(txt) and txt[index + 1] in "01234567": |
|
1125 index += 1 |
|
1126 oc += txt[index] |
|
1127 if index + 1 < len(txt) and txt[index + 1] in "01234567": |
|
1128 index += 1 |
|
1129 oc += txt[index] |
|
1130 o = chr(int(oc, base=8)) |
|
1131 elif c.lower() == "x": |
|
1132 val = 0 |
|
1133 if index + 1 < len(txt) and txt[index + 1] in "0123456789abcdefABCDEF": |
|
1134 index += 1 |
|
1135 hx = txt[index] |
|
1136 if ( |
|
1137 index + 1 < len(txt) |
|
1138 and txt[index + 1] in "0123456789abcdefABCDEF" |
|
1139 ): |
|
1140 index += 1 |
|
1141 hx += txt[index] |
|
1142 val = int(hx, base=16) |
|
1143 o = chr(val) |
|
1144 else: |
|
1145 o = c |
|
1146 else: |
|
1147 o = c |
|
1148 |
|
1149 s.append(o) |
|
1150 index += 1 |
|
1151 |
|
1152 return "".join(s) |
|
1153 |
|
1154 |
|
1155 _slashmap = {i: hex(i).replace("0x", "\\x") for i in range(7)} |
|
1156 _slashmap.update( |
|
1157 { |
|
1158 7: "\\a", |
|
1159 8: "\\b", |
|
1160 9: "\\t", |
|
1161 10: "\\n", |
|
1162 11: "\\v", |
|
1163 12: "\\f", |
|
1164 13: "\\r", |
|
1165 } |
|
1166 ) |
|
1167 _slashmap.update({i: hex(i).replace("0x", "\\x") for i in range(14, 32)}) |
|
1168 _slashmap.update({i: hex(i).replace("0x", "\\x") for i in range(127, 160)}) |
|
1169 |
|
1170 |
|
1171 def slash(txt): |
|
1172 """ |
|
1173 Function to convert an escaped string to a string containing escape codes. |
|
1174 |
|
1175 Note: This is the reverse of 'unslash()'. |
|
1176 |
|
1177 @param txt string to be converted |
|
1178 @type str |
|
1179 @return converted string containing escaped escape codes |
|
1180 @rtype str |
|
1181 """ |
|
1182 return txt.translate(_slashmap) |
1030 |
1183 |
1031 |
1184 |
1032 ############################################################################### |
1185 ############################################################################### |
1033 ## Other utility functions below |
1186 ## Other utility functions below |
1034 ############################################################################### |
1187 ############################################################################### |
1116 versions = {} |
1269 versions = {} |
1117 for pinfo in pm.getPluginInfos(): |
1270 for pinfo in pm.getPluginInfos(): |
1118 versions[pinfo["module_name"]] = pinfo["version"] |
1271 versions[pinfo["module_name"]] = pinfo["version"] |
1119 |
1272 |
1120 info.append("Plugins Version Numbers:") |
1273 info.append("Plugins Version Numbers:") |
1121 for pluginModuleName in sorted(versions.keys()): |
1274 for pluginModuleName in sorted(versions): |
1122 info.append( |
1275 info.append( |
1123 " {0} {1}".format(pluginModuleName, versions[pluginModuleName]) |
1276 " {0} {1}".format(pluginModuleName, versions[pluginModuleName]) |
1124 ) |
1277 ) |
1125 |
1278 |
1126 return linesep.join(info) |
1279 return linesep.join(info) |