118 statements. Commands and statement are always exactly one line and may be |
123 statements. Commands and statement are always exactly one line and may be |
119 interspersed. |
124 interspersed. |
120 |
125 |
121 The protocol is as follows. First the client opens a connection to the |
126 The protocol is as follows. First the client opens a connection to the |
122 debugger and then sends a series of one line commands. A command is either |
127 debugger and then sends a series of one line commands. A command is either |
123 >Load<, >Step<, >StepInto<, ... or a Python statement. |
128 >Load<, >Step<, >StepInto<, ... or a Python statement. |
124 See DebugProtocol.py for a listing of valid protocol tokens. |
129 See DebugProtocol.py for a listing of valid protocol tokens. |
125 |
130 |
126 A Python statement consists of the statement to execute, followed (in a |
131 A Python statement consists of the statement to execute, followed (in a |
127 separate line) by >OK?<. If the statement was incomplete then the response |
132 separate line) by >OK?<. If the statement was incomplete then the response |
128 is >Continue<. If there was an exception then the response is |
133 is >Continue<. If there was an exception then the response is |
129 >Exception<. |
134 >Exception<. |
130 Otherwise the response is >OK<. The reason for the >OK?< part is to |
135 Otherwise the response is >OK<. The reason for the >OK?< part is to |
131 provide a sentinal (ie. the responding >OK<) after any possible output as a |
136 provide a sentinal (ie. the responding >OK<) after any possible output as a |
132 result of executing the command. |
137 result of executing the command. |
133 |
138 |
241 if m: |
246 if m: |
242 self.__coding = m.group(1) |
247 self.__coding = m.group(1) |
243 return |
248 return |
244 self.__coding = default |
249 self.__coding = default |
245 |
250 |
246 def attachThread(self, target = None, args = None, kwargs = None, mainThread = False): |
251 def attachThread(self, target=None, args=None, kwargs=None, mainThread=False): |
247 """ |
252 """ |
248 Public method to setup a thread for DebugClient to debug. |
253 Public method to setup a thread for DebugClient to debug. |
249 |
254 |
250 If mainThread is non-zero, then we are attaching to the already |
255 If mainThread is non-zero, then we are attaching to the already |
251 started mainthread of the app and the rest of the args are ignored. |
256 started mainthread of the app and the rest of the args are ignored. |
252 |
257 |
253 @param target the start function of the target thread (i.e. the user code) |
258 @param target the start function of the target thread (i.e. the user code) |
254 @param args arguments to pass to target |
259 @param args arguments to pass to target |
255 @param kwargs keyword arguments to pass to target |
260 @param kwargs keyword arguments to pass to target |
256 @param mainThread True, if we are attaching to the already |
261 @param mainThread True, if we are attaching to the already |
257 started mainthread of the app |
262 started mainthread of the app |
258 @return The identifier of the created thread |
263 @return The identifier of the created thread |
259 """ |
264 """ |
260 if self.debugging: |
265 if self.debugging: |
261 sys.setprofile(self.profile) |
266 sys.setprofile(self.profile) |
508 self.mainFrame = None |
513 self.mainFrame = None |
509 self.botframe = None |
514 self.botframe = None |
510 self.inRawMode = False |
515 self.inRawMode = False |
511 |
516 |
512 self.threads.clear() |
517 self.threads.clear() |
513 self.attachThread(mainThread = True) |
518 self.attachThread(mainThread=True) |
514 |
519 |
515 # set the system exception handling function to ensure, that |
520 # set the system exception handling function to ensure, that |
516 # we report on all unhandled exceptions |
521 # we report on all unhandled exceptions |
517 sys.excepthook = self.__unhandled_exception |
522 sys.excepthook = self.__unhandled_exception |
518 |
523 |
519 self.mainThread.tracePython = False |
524 self.mainThread.tracePython = False |
520 |
525 |
521 self.debugMod.__dict__['__file__'] = sys.argv[0] |
526 self.debugMod.__dict__['__file__'] = sys.argv[0] |
522 sys.modules['__main__'] = self.debugMod |
527 sys.modules['__main__'] = self.debugMod |
523 exec(open(sys.argv[0], encoding = self.__coding).read(), |
528 exec(open(sys.argv[0], encoding=self.__coding).read(), |
524 self.debugMod.__dict__) |
529 self.debugMod.__dict__) |
525 self.writestream.flush() |
530 self.writestream.flush() |
526 return |
531 return |
527 |
532 |
528 if cmd == RequestProfile: |
533 if cmd == RequestProfile: |
577 # set the system exception handling function to ensure, that |
582 # set the system exception handling function to ensure, that |
578 # we report on all unhandled exceptions |
583 # we report on all unhandled exceptions |
579 sys.excepthook = self.__unhandled_exception |
584 sys.excepthook = self.__unhandled_exception |
580 |
585 |
581 # generate a coverage object |
586 # generate a coverage object |
582 self.cover = coverage(auto_data = True, |
587 self.cover = coverage(auto_data=True, |
583 data_file = "{0}.coverage".format(os.path.splitext(sys.argv[0])[0])) |
588 data_file="{0}.coverage".format(os.path.splitext(sys.argv[0])[0])) |
584 self.cover.use_cache(True) |
589 self.cover.use_cache(True) |
585 |
590 |
586 if int(erase): |
591 if int(erase): |
587 self.cover.erase() |
592 self.cover.erase() |
588 sys.modules['__main__'] = self.debugMod |
593 sys.modules['__main__'] = self.debugMod |
589 self.debugMod.__dict__['__file__'] = sys.argv[0] |
594 self.debugMod.__dict__['__file__'] = sys.argv[0] |
590 self.cover.start() |
595 self.cover.start() |
591 exec(open(sys.argv[0], encoding = self.__coding).read(), |
596 exec(open(sys.argv[0], encoding=self.__coding).read(), |
592 self.debugMod.__dict__) |
597 self.debugMod.__dict__) |
593 self.cover.stop() |
598 self.cover.stop() |
594 self.cover.save() |
599 self.cover.save() |
595 self.writestream.flush() |
600 self.writestream.flush() |
596 return |
601 return |
749 self.write(ResponseException + '\n') |
754 self.write(ResponseException + '\n') |
750 |
755 |
751 return |
756 return |
752 |
757 |
753 if cmd == RequestBanner: |
758 if cmd == RequestBanner: |
754 self.write('{0}{1}\n'.format(ResponseBanner, |
759 self.write('{0}{1}\n'.format(ResponseBanner, |
755 str(("Python {0}".format(sys.version), |
760 str(("Python {0}".format(sys.version), |
756 socket.gethostname(), self.variant)))) |
761 socket.gethostname(), self.variant)))) |
757 return |
762 return |
758 |
763 |
759 if cmd == RequestCapabilities: |
764 if cmd == RequestCapabilities: |
760 self.write('{0}{1:d}, "Python3"\n'.format(ResponseCapabilities, |
765 self.write('{0}{1:d}, "Python3"\n'.format(ResponseCapabilities, |
761 self.__clientCapabilities())) |
766 self.__clientCapabilities())) |
762 return |
767 return |
763 |
768 |
764 if cmd == RequestCompletion: |
769 if cmd == RequestCompletion: |
765 self.__completionList(arg.replace("u'", "'")) |
770 self.__completionList(arg.replace("u'", "'")) |
1036 self.writeReady(self.writestream.fileno()) |
1041 self.writeReady(self.writestream.fileno()) |
1037 |
1042 |
1038 if self.errorstream in wrdy: |
1043 if self.errorstream in wrdy: |
1039 self.writeReady(self.errorstream.fileno()) |
1044 self.writeReady(self.errorstream.fileno()) |
1040 |
1045 |
1041 def connectDebugger(self, port, remoteAddress = None, redirect = True): |
1046 def connectDebugger(self, port, remoteAddress=None, redirect=True): |
1042 """ |
1047 """ |
1043 Public method to establish a session with the debugger. |
1048 Public method to establish a session with the debugger. |
1044 |
1049 |
1045 It opens a network connection to the debugger, connects it to stdin, |
1050 It opens a network connection to the debugger, connects it to stdin, |
1046 stdout and stderr and saves these file objects in case the application |
1051 stdout and stderr and saves these file objects in case the application |
1047 being debugged redirects them itself. |
1052 being debugged redirects them itself. |
1048 |
1053 |
1049 @param port the port number to connect to (int) |
1054 @param port the port number to connect to (int) |
1050 @param remoteAddress the network address of the debug server host (string) |
1055 @param remoteAddress the network address of the debug server host (string) |
1365 i += 1 |
1369 i += 1 |
1366 |
1370 |
1367 if ("sipThis" in dict.keys() and len(dict) == 1) or \ |
1371 if ("sipThis" in dict.keys() and len(dict) == 1) or \ |
1368 (len(dict) == 0 and len(udict) > 0): |
1372 (len(dict) == 0 and len(udict) > 0): |
1369 if access: |
1373 if access: |
1370 loc = {"udict" : udict} |
1374 loc = {"udict": udict} |
1371 exec('qvar = udict{0!s}'.format(access), globals(), loc) |
1375 exec('qvar = udict{0!s}'.format(access), globals(), loc) |
1372 qvar = loc["qvar"] |
1376 qvar = loc["qvar"] |
1373 # this has to be in line with VariablesViewer.indicators |
1377 # this has to be in line with VariablesViewer.indicators |
1374 elif rvar and rvar[0][-2:] in ["[]", "()", "{}"]: |
1378 elif rvar and rvar[0][-2:] in ["[]", "()", "{}"]: |
1375 loc = {"udict" : udict} |
1379 loc = {"udict": udict} |
1376 exec('qvar = udict["{0!s}"][{1!s}]'.format(rvar[0][:-2], rvar[1]), |
1380 exec('qvar = udict["{0!s}"][{1!s}]'.format(rvar[0][:-2], rvar[1]), |
1377 globals(), loc) |
1381 globals(), loc) |
1378 qvar = loc["qvar"] |
1382 qvar = loc["qvar"] |
1379 else: |
1383 else: |
1380 qvar = udict[var[-1]] |
1384 qvar = udict[var[-1]] |
1381 qvtype = str(type(qvar))[1:-1].split()[1][1:-1] |
1385 qvtype = str(type(qvar))[1:-1].split()[1][1:-1] |
1388 if dictkeys is None: |
1392 if dictkeys is None: |
1389 dictkeys = dict.keys() |
1393 dictkeys = dict.keys() |
1390 else: |
1394 else: |
1391 # treatment for sequences and dictionaries |
1395 # treatment for sequences and dictionaries |
1392 if access: |
1396 if access: |
1393 loc = {"dict" : dict} |
1397 loc = {"dict": dict} |
1394 exec("dict = dict{0!s}".format(access), globals(), loc) |
1398 exec("dict = dict{0!s}".format(access), globals(), loc) |
1395 dict = loc["dict"] |
1399 dict = loc["dict"] |
1396 else: |
1400 else: |
1397 dict = dict[dictkeys[0]] |
1401 dict = dict[dictkeys[0]] |
1398 if isDict: |
1402 if isDict: |
1399 dictkeys = dict.keys() |
1403 dictkeys = dict.keys() |
1400 else: |
1404 else: |
1401 dictkeys = range(len(dict)) |
1405 dictkeys = range(len(dict)) |
1402 vlist = self.__formatVariablesList(dictkeys, dict, scope, filter, |
1406 vlist = self.__formatVariablesList(dictkeys, dict, scope, filter, |
1403 formatSequences) |
1407 formatSequences) |
1404 varlist.extend(vlist) |
1408 varlist.extend(vlist) |
1405 |
1409 |
1406 if obj is not None and not formatSequences: |
1410 if obj is not None and not formatSequences: |
1407 if repr(obj).startswith('{'): |
1411 if repr(obj).startswith('{'): |
1451 varlist.append(("width", "float", "{0:g}".format(value.width()))) |
1455 varlist.append(("width", "float", "{0:g}".format(value.width()))) |
1452 varlist.append(("height", "float", "{0:g}".format(value.height()))) |
1456 varlist.append(("height", "float", "{0:g}".format(value.height()))) |
1453 elif qttype == 'QColor': |
1457 elif qttype == 'QColor': |
1454 varlist.append(("name", "str", "{0}".format(value.name()))) |
1458 varlist.append(("name", "str", "{0}".format(value.name()))) |
1455 r, g, b, a = value.getRgb() |
1459 r, g, b, a = value.getRgb() |
1456 varlist.append(("rgb", "int", |
1460 varlist.append(("rgb", "int", |
1457 "{0:d}, {1:d}, {2:d}, {3:d}".format(r, g, b, a))) |
1461 "{0:d}, {1:d}, {2:d}, {3:d}".format(r, g, b, a))) |
1458 h, s, v, a = value.getHsv() |
1462 h, s, v, a = value.getHsv() |
1459 varlist.append(("hsv", "int", |
1463 varlist.append(("hsv", "int", |
1460 "{0:d}, {1:d}, {2:d}, {3:d}".format(h, s, v, a))) |
1464 "{0:d}, {1:d}, {2:d}, {3:d}".format(h, s, v, a))) |
1461 c, m, y, k, a = value.getCmyk() |
1465 c, m, y, k, a = value.getCmyk() |
1462 varlist.append(("cmyk", "int", |
1466 varlist.append(("cmyk", "int", |
1463 "{0:d}, {1:d}, {2:d}, {3:d}, {4:d}".format(c, m, y, k, a))) |
1467 "{0:d}, {1:d}, {2:d}, {3:d}, {4:d}".format(c, m, y, k, a))) |
1464 elif qttype == 'QDate': |
1468 elif qttype == 'QDate': |
1465 varlist.append(("", "QDate", "{0}".format(value.toString()))) |
1469 varlist.append(("", "QDate", "{0}".format(value.toString()))) |
1466 elif qttype == 'QTime': |
1470 elif qttype == 'QTime': |
1467 varlist.append(("", "QTime", "{0}".format(value.toString()))) |
1471 varlist.append(("", "QTime", "{0}".format(value.toString()))) |
1468 elif qttype == 'QDateTime': |
1472 elif qttype == 'QDateTime': |
1469 varlist.append(("", "QDateTime", "{0}".format(value.toString()))) |
1473 varlist.append(("", "QDateTime", "{0}".format(value.toString()))) |
1470 elif qttype == 'QDir': |
1474 elif qttype == 'QDir': |
1471 varlist.append(("path", "str", "{0}".format(value.path()))) |
1475 varlist.append(("path", "str", "{0}".format(value.path()))) |
1472 varlist.append(("absolutePath", "str", |
1476 varlist.append(("absolutePath", "str", |
1473 "{0}".format(value.absolutePath()))) |
1477 "{0}".format(value.absolutePath()))) |
1474 varlist.append(("canonicalPath", "str", |
1478 varlist.append(("canonicalPath", "str", |
1475 "{0}".format(value.canonicalPath()))) |
1479 "{0}".format(value.canonicalPath()))) |
1476 elif qttype == 'QFile': |
1480 elif qttype == 'QFile': |
1477 varlist.append(("fileName", "str", "{0}".format(value.fileName()))) |
1481 varlist.append(("fileName", "str", "{0}".format(value.fileName()))) |
1478 elif qttype == 'QFont': |
1482 elif qttype == 'QFont': |
1479 varlist.append(("family", "str", "{0}".format(value.family()))) |
1483 varlist.append(("family", "str", "{0}".format(value.family()))) |
1493 varlist.append(("valid", "bool", "{0}".format(value.isValid()))) |
1497 varlist.append(("valid", "bool", "{0}".format(value.isValid()))) |
1494 if value.isValid(): |
1498 if value.isValid(): |
1495 varlist.append(("row", "int", "{0}".format(value.row()))) |
1499 varlist.append(("row", "int", "{0}".format(value.row()))) |
1496 varlist.append(("column", "int", "{0}".format(value.column()))) |
1500 varlist.append(("column", "int", "{0}".format(value.column()))) |
1497 varlist.append(("internalId", "int", "{0}".format(value.internalId()))) |
1501 varlist.append(("internalId", "int", "{0}".format(value.internalId()))) |
1498 varlist.append(("internalPointer", "void *", |
1502 varlist.append(("internalPointer", "void *", |
1499 "{0}".format(value.internalPointer()))) |
1503 "{0}".format(value.internalPointer()))) |
1500 elif qttype == 'QRegExp': |
1504 elif qttype == 'QRegExp': |
1501 varlist.append(("pattern", "str", "{0}".format(value.pattern()))) |
1505 varlist.append(("pattern", "str", "{0}".format(value.pattern()))) |
1502 |
1506 |
1503 # GUI stuff |
1507 # GUI stuff |
1505 varlist.append(("name", "str", "{0}".format(value.objectName()))) |
1509 varlist.append(("name", "str", "{0}".format(value.objectName()))) |
1506 varlist.append(("text", "str", "{0}".format(value.text()))) |
1510 varlist.append(("text", "str", "{0}".format(value.text()))) |
1507 varlist.append(("icon text", "str", "{0}".format(value.iconText()))) |
1511 varlist.append(("icon text", "str", "{0}".format(value.iconText()))) |
1508 varlist.append(("tooltip", "str", "{0}".format(value.toolTip()))) |
1512 varlist.append(("tooltip", "str", "{0}".format(value.toolTip()))) |
1509 varlist.append(("whatsthis", "str", "{0}".format(value.whatsThis()))) |
1513 varlist.append(("whatsthis", "str", "{0}".format(value.whatsThis()))) |
1510 varlist.append(("shortcut", "str", |
1514 varlist.append(("shortcut", "str", |
1511 "{0}".format(value.shortcut().toString()))) |
1515 "{0}".format(value.shortcut().toString()))) |
1512 elif qttype == 'QKeySequence': |
1516 elif qttype == 'QKeySequence': |
1513 varlist.append(("value", "", "{0}".format(value.toString()))) |
1517 varlist.append(("value", "", "{0}".format(value.toString()))) |
1514 |
1518 |
1515 # XML stuff |
1519 # XML stuff |
1532 elif qttype == 'QHostAddress': |
1536 elif qttype == 'QHostAddress': |
1533 varlist.append(("address", "QHostAddress", "{0}".format(value.toString()))) |
1537 varlist.append(("address", "QHostAddress", "{0}".format(value.toString()))) |
1534 |
1538 |
1535 return varlist |
1539 return varlist |
1536 |
1540 |
1537 def __formatVariablesList(self, keylist, dict, scope, filter = [], |
1541 def __formatVariablesList(self, keylist, dict, scope, filter=[], |
1538 formatSequences = False): |
1542 formatSequences=False): |
1539 """ |
1543 """ |
1540 Private method to produce a formated variables list. |
1544 Private method to produce a formated variables list. |
1541 |
1545 |
1542 The dictionary passed in to it is scanned. Variables are |
1546 The dictionary passed in to it is scanned. Variables are |
1543 only added to the list, if their type is not contained |
1547 only added to the list, if their type is not contained |
1544 in the filter list and their name doesn't match any of the filter expressions. |
1548 in the filter list and their name doesn't match any of the filter expressions. |
1545 The formated variables list (a list of tuples of 3 values) is returned. |
1549 The formated variables list (a list of tuples of 3 values) is returned. |
1546 |
1550 |
1547 @param keylist keys of the dictionary |
1551 @param keylist keys of the dictionary |
1548 @param dict the dictionary to be scanned |
1552 @param dict the dictionary to be scanned |
1549 @param scope 1 to filter using the globals filter, 0 using the locals |
1553 @param scope 1 to filter using the globals filter, 0 using the locals |
1550 filter (int). |
1554 filter (int). |
1551 Variables are only added to the list, if their name do not match any of the |
1555 Variables are only added to the list, if their name do not match any of the |
1552 filter expressions. |
1556 filter expressions. |
1553 @param filter the indices of variable types to be filtered. Variables are |
1557 @param filter the indices of variable types to be filtered. Variables are |
1554 only added to the list, if their type is not contained in the filter |
1558 only added to the list, if their type is not contained in the filter |
1555 list. |
1559 list. |
1556 @param formatSequences flag indicating, that sequence or dictionary variables |
1560 @param formatSequences flag indicating, that sequence or dictionary variables |
1557 should be formatted. If it is 0 (or false), just the number of items contained |
1561 should be formatted. If it is 0 (or false), just the number of items contained |
1558 in these variables is returned. (boolean) |
1562 in these variables is returned. (boolean) |
1559 @return A tuple consisting of a list of formatted variables. Each variable |
1563 @return A tuple consisting of a list of formatted variables. Each variable |
1560 entry is a tuple of three elements, the variable name, its type and |
1564 entry is a tuple of three elements, the variable name, its type and |
1561 value. |
1565 value. |
1562 """ |
1566 """ |
1563 varlist = [] |
1567 varlist = [] |
1564 if scope: |
1568 if scope: |
1565 patternFilterObjects = self.globalsFilterObjects |
1569 patternFilterObjects = self.globalsFilterObjects |
1717 self.dircache = [] |
1721 self.dircache = [] |
1718 self.mainFrame = None |
1722 self.mainFrame = None |
1719 self.inRawMode = False |
1723 self.inRawMode = False |
1720 self.debugging = True |
1724 self.debugging = True |
1721 |
1725 |
1722 self.attachThread(mainThread = True) |
1726 self.attachThread(mainThread=True) |
1723 self.mainThread.tracePython = tracePython |
1727 self.mainThread.tracePython = tracePython |
1724 |
1728 |
1725 # set the system exception handling function to ensure, that |
1729 # set the system exception handling function to ensure, that |
1726 # we report on all unhandled exceptions |
1730 # we report on all unhandled exceptions |
1727 sys.excepthook = self.__unhandled_exception |
1731 sys.excepthook = self.__unhandled_exception |
1728 |
1732 |
1729 # now start debugging |
1733 # now start debugging |
1730 if enableTrace: |
1734 if enableTrace: |
1731 self.mainThread.set_trace() |
1735 self.mainThread.set_trace() |
1732 |
1736 |
1733 def startProgInDebugger(self, progargs, wd = '', host = None, |
1737 def startProgInDebugger(self, progargs, wd='', host=None, |
1734 port = None, exceptions = True, tracePython = False, redirect = True): |
1738 port=None, exceptions=True, tracePython=False, redirect=True): |
1735 """ |
1739 """ |
1736 Public method used to start the remote debugger. |
1740 Public method used to start the remote debugger. |
1737 |
1741 |
1738 @param progargs commandline for the program to be debugged |
1742 @param progargs commandline for the program to be debugged |
1739 (list of strings) |
1743 (list of strings) |
1740 @param wd working directory for the program execution (string) |
1744 @param wd working directory for the program execution (string) |
1741 @param host hostname of the debug server (string) |
1745 @param host hostname of the debug server (string) |
1742 @param port portnumber of the debug server (int) |
1746 @param port portnumber of the debug server (int) |
1743 @param exceptions flag to enable exception reporting of the IDE (boolean) |
1747 @param exceptions flag to enable exception reporting of the IDE (boolean) |
1865 if not args: |
1869 if not args: |
1866 print("No program given. Aborting!") |
1870 print("No program given. Aborting!") |
1867 else: |
1871 else: |
1868 if not self.noencoding: |
1872 if not self.noencoding: |
1869 self.__coding = self.defaultCoding |
1873 self.__coding = self.defaultCoding |
1870 self.startProgInDebugger(args, wd, host, port, |
1874 self.startProgInDebugger(args, wd, host, port, |
1871 exceptions = exceptions, |
1875 exceptions=exceptions, |
1872 tracePython = tracePython, |
1876 tracePython=tracePython, |
1873 redirect = redirect) |
1877 redirect=redirect) |
1874 else: |
1878 else: |
1875 if sys.argv[1] == '--no-encoding': |
1879 if sys.argv[1] == '--no-encoding': |
1876 self.noencoding = True |
1880 self.noencoding = True |
1877 del sys.argv[1] |
1881 del sys.argv[1] |
1878 if sys.argv[1] == '': |
1882 if sys.argv[1] == '': |
1934 |
1938 |
1935 It prevents the debugger connections from being closed. |
1939 It prevents the debugger connections from being closed. |
1936 |
1940 |
1937 @param fd file descriptor to be closed (integer) |
1941 @param fd file descriptor to be closed (integer) |
1938 """ |
1942 """ |
1939 if fd in [self.readstream.fileno(), self.writestream.fileno(), |
1943 if fd in [self.readstream.fileno(), self.writestream.fileno(), |
1940 self.errorstream.fileno()]: |
1944 self.errorstream.fileno()]: |
1941 return |
1945 return |
1942 |
1946 |
1943 DebugClientOrigClose(fd) |
1947 DebugClientOrigClose(fd) |
1944 |
1948 |
1945 def __getSysPath(self, firstEntry): |
1949 def __getSysPath(self, firstEntry): |
1946 """ |
1950 """ |
1947 Private slot to calculate a path list including the PYTHONPATH |
1951 Private slot to calculate a path list including the PYTHONPATH |
1948 environment variable. |
1952 environment variable. |
1949 |
1953 |
1950 @param firstEntry entry to be put first in sys.path (string) |
1954 @param firstEntry entry to be put first in sys.path (string) |
1951 @return path list for use as sys.path (list of strings) |
1955 @return path list for use as sys.path (list of strings) |
1952 """ |
1956 """ |
1953 sysPath = [path for path in os.environ.get("PYTHONPATH", "").split(os.pathsep) |
1957 sysPath = [path for path in os.environ.get("PYTHONPATH", "").split(os.pathsep) |
1954 if path not in sys.path] + sys.path[:] |
1958 if path not in sys.path] + sys.path[:] |
1955 if "" in sysPath: |
1959 if "" in sysPath: |
1956 sysPath.remove("") |
1960 sysPath.remove("") |
1957 sysPath.insert(0, firstEntry) |
1961 sysPath.insert(0, firstEntry) |
1958 sysPath.insert(0, '') |
1962 sysPath.insert(0, '') |