Vendor debugpy for VS Code attach debugging
Bundles debugpy 1.7.0 directly in python/ so "Maya: Attach (debugpy)" works with no per-machine pip install step. Installed via Maya 2022's own pip so it resolved a version actually compatible with Python 3.7 (Maya 2022's interpreter), then verified import + listen() succeeds under all three target Maya Python versions (3.7/3.9/3.10). Also fixes a latent __file__-under-exec() bug in start_debug_server.py (same pitfall as Maya's own plugin loader, never hit until this exercised it) and corrects the README's Maya Python version claim -- 2022 ships Python 3.7, not 3.9 as previously stated, which was never independently verified until now. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import threading
|
||||
import unittest
|
||||
import os
|
||||
import pytest
|
||||
import pydevconsole
|
||||
|
||||
from _pydev_bundle.pydev_imports import xmlrpclib, SimpleXMLRPCServer
|
||||
from _pydev_bundle.pydev_localhost import get_localhost
|
||||
|
||||
try:
|
||||
raw_input
|
||||
raw_input_name = 'raw_input'
|
||||
except NameError:
|
||||
raw_input_name = 'input'
|
||||
|
||||
try:
|
||||
from IPython import core # @UnusedImport
|
||||
has_ipython = True
|
||||
except:
|
||||
has_ipython = False
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
# Test
|
||||
#=======================================================================================================================
|
||||
@pytest.mark.skipif(os.environ.get('TRAVIS') == 'true' or not has_ipython, reason='Too flaky on Travis (and requires IPython).')
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def start_client_thread(self, client_port):
|
||||
class ClientThread(threading.Thread):
|
||||
def __init__(self, client_port):
|
||||
threading.Thread.__init__(self)
|
||||
self.client_port = client_port
|
||||
|
||||
def run(self):
|
||||
class HandleRequestInput:
|
||||
def RequestInput(self):
|
||||
client_thread.requested_input = True
|
||||
return 'RequestInput: OK'
|
||||
|
||||
def NotifyFinished(self, *args, **kwargs):
|
||||
client_thread.notified_finished += 1
|
||||
return 1
|
||||
|
||||
handle_request_input = HandleRequestInput()
|
||||
|
||||
from _pydev_bundle import pydev_localhost
|
||||
self.client_server = client_server = SimpleXMLRPCServer((pydev_localhost.get_localhost(), self.client_port), logRequests=False)
|
||||
client_server.register_function(handle_request_input.RequestInput)
|
||||
client_server.register_function(handle_request_input.NotifyFinished)
|
||||
client_server.serve_forever()
|
||||
|
||||
def shutdown(self):
|
||||
return
|
||||
self.client_server.shutdown()
|
||||
|
||||
client_thread = ClientThread(client_port)
|
||||
client_thread.requested_input = False
|
||||
client_thread.notified_finished = 0
|
||||
client_thread.daemon = True
|
||||
client_thread.start()
|
||||
return client_thread
|
||||
|
||||
|
||||
def get_free_addresses(self):
|
||||
from _pydev_bundle.pydev_localhost import get_socket_names
|
||||
socket_names = get_socket_names(2, close=True)
|
||||
return [socket_name[1] for socket_name in socket_names]
|
||||
|
||||
def test_server(self):
|
||||
# Just making sure that the singleton is created in this thread.
|
||||
from _pydev_bundle.pydev_ipython_console_011 import get_pydev_frontend
|
||||
get_pydev_frontend(get_localhost(), 0)
|
||||
|
||||
client_port, server_port = self.get_free_addresses()
|
||||
class ServerThread(threading.Thread):
|
||||
def __init__(self, client_port, server_port):
|
||||
threading.Thread.__init__(self)
|
||||
self.client_port = client_port
|
||||
self.server_port = server_port
|
||||
|
||||
def run(self):
|
||||
from _pydev_bundle import pydev_localhost
|
||||
print('Starting server with:', pydev_localhost.get_localhost(), self.server_port, self.client_port)
|
||||
pydevconsole.start_server(pydev_localhost.get_localhost(), self.server_port, self.client_port)
|
||||
server_thread = ServerThread(client_port, server_port)
|
||||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
client_thread = self.start_client_thread(client_port) #@UnusedVariable
|
||||
|
||||
try:
|
||||
import time
|
||||
time.sleep(.3) #let's give it some time to start the threads
|
||||
|
||||
from _pydev_bundle import pydev_localhost
|
||||
server = xmlrpclib.Server('http://%s:%s' % (pydev_localhost.get_localhost(), server_port))
|
||||
server.execLine("import sys; print('Running with: %s %s' % (sys.executable or sys.platform, sys.version))")
|
||||
server.execLine('class Foo:')
|
||||
server.execLine(' pass')
|
||||
server.execLine('')
|
||||
server.execLine('foo = Foo()')
|
||||
server.execLine('a = %s()' % raw_input_name)
|
||||
initial = time.time()
|
||||
while not client_thread.requested_input:
|
||||
if time.time() - initial > 2:
|
||||
raise AssertionError('Did not get the return asked before the timeout.')
|
||||
time.sleep(.1)
|
||||
frame_xml = server.getFrame()
|
||||
self.assertTrue('RequestInput' in frame_xml, 'Did not fid RequestInput in:\n%s' % (frame_xml,))
|
||||
finally:
|
||||
client_thread.shutdown()
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
import pytest
|
||||
from _pydevd_bundle import pydevd_referrers
|
||||
from io import StringIO
|
||||
from tests_python.debugger_unittest import IS_PYPY
|
||||
|
||||
try:
|
||||
import gc
|
||||
gc.get_referrers(unittest)
|
||||
has_referrers = True
|
||||
except NotImplementedError:
|
||||
has_referrers = False
|
||||
|
||||
|
||||
# Only do get referrers tests if it's actually available.
|
||||
@pytest.mark.skipif(not has_referrers or IS_PYPY, reason='gc.get_referrers not implemented')
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def test_get_referrers1(self):
|
||||
|
||||
container = []
|
||||
contained = [1, 2]
|
||||
container.append(0)
|
||||
container.append(contained)
|
||||
|
||||
# Ok, we have the contained in this frame and inside the given list (which on turn is in this frame too).
|
||||
# we should skip temporary references inside the get_referrer_info.
|
||||
result = pydevd_referrers.get_referrer_info(contained)
|
||||
assert 'list[1]' in result
|
||||
pydevd_referrers.print_referrers(contained, stream=StringIO())
|
||||
|
||||
def test_get_referrers2(self):
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
contained = [1, 2]
|
||||
obj = MyClass()
|
||||
obj.contained = contained
|
||||
del contained
|
||||
|
||||
# Ok, we have the contained in this frame and inside the given list (which on turn is in this frame too).
|
||||
# we should skip temporary references inside the get_referrer_info.
|
||||
result = pydevd_referrers.get_referrer_info(obj.contained)
|
||||
assert 'found_as="contained"' in result
|
||||
assert 'MyClass' in result
|
||||
|
||||
def test_get_referrers3(self):
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
contained = [1, 2]
|
||||
obj = MyClass()
|
||||
obj.contained = contained
|
||||
del contained
|
||||
|
||||
# Ok, we have the contained in this frame and inside the given list (which on turn is in this frame too).
|
||||
# we should skip temporary references inside the get_referrer_info.
|
||||
result = pydevd_referrers.get_referrer_info(obj.contained)
|
||||
assert 'found_as="contained"' in result
|
||||
assert 'MyClass' in result
|
||||
|
||||
def test_get_referrers4(self):
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
obj = MyClass()
|
||||
obj.me = obj
|
||||
|
||||
# Let's see if we detect the cycle...
|
||||
result = pydevd_referrers.get_referrer_info(obj)
|
||||
assert 'found_as="me"' in result # Cyclic ref
|
||||
|
||||
def test_get_referrers5(self):
|
||||
container = dict(a=[1])
|
||||
|
||||
# Let's see if we detect the cycle...
|
||||
result = pydevd_referrers.get_referrer_info(container['a'])
|
||||
assert 'test_get_referrers5' not in result # I.e.: NOT in the current method
|
||||
assert 'found_as="a"' in result
|
||||
assert 'dict' in result
|
||||
assert str(id(container)) in result
|
||||
|
||||
def test_get_referrers6(self):
|
||||
import sys
|
||||
container = dict(a=[1])
|
||||
|
||||
def should_appear(obj):
|
||||
# Let's see if we detect the cycle...
|
||||
return pydevd_referrers.get_referrer_info(obj)
|
||||
|
||||
result = should_appear(container['a'])
|
||||
if sys.version_info[:2] >= (3, 7):
|
||||
# In Python 3.7 the frame is not appearing in gc.get_referrers.
|
||||
assert 'should_appear' not in result
|
||||
else:
|
||||
assert 'should_appear' in result
|
||||
|
||||
def test_get_referrers7(self):
|
||||
|
||||
class MyThread(threading.Thread):
|
||||
|
||||
def run(self):
|
||||
# Note: we do that because if we do
|
||||
self.frame = sys._getframe()
|
||||
|
||||
t = MyThread()
|
||||
t.start()
|
||||
while not hasattr(t, 'frame'):
|
||||
time.sleep(0.01)
|
||||
|
||||
result = pydevd_referrers.get_referrer_info(t.frame)
|
||||
assert 'MyThread' in result
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
'''
|
||||
@author Fabio Zadrozny
|
||||
'''
|
||||
import sys
|
||||
import unittest
|
||||
import socket
|
||||
import urllib
|
||||
import pytest
|
||||
import pycompletionserver
|
||||
|
||||
|
||||
IS_JYTHON = sys.platform.find('java') != -1
|
||||
DEBUG = 0
|
||||
|
||||
def dbg(s):
|
||||
if DEBUG:
|
||||
sys.stdout.write('TEST %s\n' % s)
|
||||
|
||||
@pytest.mark.skipif(not IS_JYTHON, reason='Jython related test')
|
||||
class TestJython(unittest.TestCase):
|
||||
|
||||
def test_it(self):
|
||||
dbg('ok')
|
||||
|
||||
|
||||
def test_message(self):
|
||||
t = pycompletionserver.CompletionServer(0)
|
||||
t.exit_process_on_kill = False
|
||||
|
||||
l = []
|
||||
l.append(('Def', 'description' , 'args'))
|
||||
l.append(('Def1', 'description1', 'args1'))
|
||||
l.append(('Def2', 'description2', 'args2'))
|
||||
|
||||
msg = t.processor.format_completion_message('test_jyserver.py', l)
|
||||
|
||||
self.assertEqual('@@COMPLETIONS(test_jyserver.py,(Def,description,args),(Def1,description1,args1),(Def2,description2,args2))END@@', msg)
|
||||
|
||||
l = []
|
||||
l.append(('Def', 'desc,,r,,i()ption', ''))
|
||||
l.append(('Def(1', 'descriptio(n1', ''))
|
||||
l.append(('De,f)2', 'de,s,c,ription2', ''))
|
||||
msg = t.processor.format_completion_message(None, l)
|
||||
expected = '@@COMPLETIONS(None,(Def,desc%2C%2Cr%2C%2Ci%28%29ption, ),(Def%281,descriptio%28n1, ),(De%2Cf%292,de%2Cs%2Cc%2Cription2, ))END@@'
|
||||
|
||||
self.assertEqual(expected, msg)
|
||||
|
||||
|
||||
def test_completion_sockets_and_messages(self):
|
||||
dbg('test_completion_sockets_and_messages')
|
||||
t, socket = self.create_connections()
|
||||
self.socket = socket
|
||||
dbg('connections created')
|
||||
|
||||
try:
|
||||
#now that we have the connections all set up, check the code completion messages.
|
||||
msg = urllib.quote_plus('math')
|
||||
|
||||
toWrite = '@@IMPORTS:%sEND@@' % msg
|
||||
dbg('writing' + str(toWrite))
|
||||
socket.send(toWrite) #math completions
|
||||
completions = self.read_msg()
|
||||
dbg(urllib.unquote_plus(completions))
|
||||
|
||||
start = '@@COMPLETIONS('
|
||||
self.assertTrue(completions.startswith(start), '%s DOESNT START WITH %s' % (completions, start))
|
||||
self.assertTrue(completions.find('@@COMPLETIONS') != -1)
|
||||
self.assertTrue(completions.find('END@@') != -1)
|
||||
|
||||
|
||||
msg = urllib.quote_plus('__builtin__.str')
|
||||
toWrite = '@@IMPORTS:%sEND@@' % msg
|
||||
dbg('writing' + str(toWrite))
|
||||
socket.send(toWrite) #math completions
|
||||
completions = self.read_msg()
|
||||
dbg(urllib.unquote_plus(completions))
|
||||
|
||||
start = '@@COMPLETIONS('
|
||||
self.assertTrue(completions.startswith(start), '%s DOESNT START WITH %s' % (completions, start))
|
||||
self.assertTrue(completions.find('@@COMPLETIONS') != -1)
|
||||
self.assertTrue(completions.find('END@@') != -1)
|
||||
|
||||
|
||||
|
||||
finally:
|
||||
try:
|
||||
self.send_kill_msg(socket)
|
||||
|
||||
|
||||
while not t.ended:
|
||||
pass #wait until it receives the message and quits.
|
||||
|
||||
|
||||
socket.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_free_port(self):
|
||||
from _pydev_bundle.pydev_localhost import get_socket_name
|
||||
return get_socket_name(close=True)[1]
|
||||
|
||||
def create_connections(self):
|
||||
'''
|
||||
Creates the connections needed for testing.
|
||||
'''
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.bind((pycompletionserver.HOST, 0))
|
||||
server.listen(1) #socket to receive messages.
|
||||
|
||||
from thread import start_new_thread
|
||||
t = pycompletionserver.CompletionServer(server.getsockname()[1])
|
||||
t.exit_process_on_kill = False
|
||||
|
||||
start_new_thread(t.run, ())
|
||||
|
||||
sock, _addr = server.accept()
|
||||
|
||||
return t, sock
|
||||
|
||||
def read_msg(self):
|
||||
msg = '@@PROCESSING_END@@'
|
||||
while msg.startswith('@@PROCESSING'):
|
||||
msg = self.socket.recv(1024)
|
||||
if msg.startswith('@@PROCESSING:'):
|
||||
dbg('Status msg:' + str(msg))
|
||||
|
||||
while msg.find('END@@') == -1:
|
||||
msg += self.socket.recv(1024)
|
||||
|
||||
return msg
|
||||
|
||||
def send_kill_msg(self, socket):
|
||||
socket.send(pycompletionserver.MSG_KILL_SERVER)
|
||||
|
||||
|
||||
|
||||
|
||||
# Run for jython in command line:
|
||||
# c:\bin\jython2.7.0\bin\jython.exe -m py.test tests\test_jyserver.py
|
||||
@@ -0,0 +1,242 @@
|
||||
import unittest
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
# Note: ant.jar and junit.jar must be in the PYTHONPATH (see jython_test_deps)
|
||||
|
||||
IS_JYTHON = False
|
||||
if sys.platform.find('java') != -1:
|
||||
IS_JYTHON = True
|
||||
from _pydev_bundle._pydev_jy_imports_tipper import ismethod
|
||||
from _pydev_bundle._pydev_jy_imports_tipper import isclass
|
||||
from _pydev_bundle._pydev_jy_imports_tipper import dir_obj
|
||||
from _pydev_bundle import _pydev_jy_imports_tipper
|
||||
from java.lang.reflect import Method # @UnresolvedImport
|
||||
from java.lang import System # @UnresolvedImport
|
||||
from java.lang import String # @UnresolvedImport
|
||||
from java.lang.System import arraycopy # @UnresolvedImport
|
||||
from java.lang.System import out # @UnresolvedImport
|
||||
import java.lang.String # @UnresolvedImport
|
||||
import org.python.core.PyDictionary # @UnresolvedImport
|
||||
|
||||
__DBG = 0
|
||||
|
||||
|
||||
def dbg(s):
|
||||
if __DBG:
|
||||
sys.stdout.write('%s\n' % (s,))
|
||||
|
||||
|
||||
@pytest.mark.skipif(not IS_JYTHON, reason='Jython related test')
|
||||
class TestMod(unittest.TestCase):
|
||||
|
||||
def assert_args(self, tok, args, tips):
|
||||
for a in tips:
|
||||
if tok == a[0]:
|
||||
self.assertEqual(args, a[2])
|
||||
return
|
||||
raise AssertionError('%s not in %s', tok, tips)
|
||||
|
||||
def assert_in(self, tok, tips):
|
||||
self.assertEqual(4, len(tips[0]))
|
||||
for a in tips:
|
||||
if tok == a[0]:
|
||||
return a
|
||||
s = ''
|
||||
for a in tips:
|
||||
s += str(a)
|
||||
s += '\n'
|
||||
raise AssertionError('%s not in %s' % (tok, s))
|
||||
|
||||
def test_imports1a(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('java.util.HashMap')
|
||||
if f is None:
|
||||
return # Not ok with java 9
|
||||
|
||||
assert f.endswith('rt.jar')
|
||||
|
||||
def test_imports1c(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('java.lang.Class')
|
||||
if f is None:
|
||||
return # Not ok with java 9
|
||||
assert f.endswith('rt.jar')
|
||||
|
||||
def test_imports1b(self):
|
||||
try:
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('__builtin__.m')
|
||||
self.fail('err')
|
||||
except:
|
||||
pass
|
||||
|
||||
def test_imports1(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('junit.framework.TestCase')
|
||||
assert f.endswith('junit.jar')
|
||||
ret = self.assert_in('assertEquals', tip)
|
||||
# self.assertEqual('', ret[2])
|
||||
|
||||
def test_imports2(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('junit.framework')
|
||||
assert f.endswith('junit.jar')
|
||||
ret = self.assert_in('TestCase', tip)
|
||||
self.assertEqual('', ret[2])
|
||||
|
||||
def test_imports2a(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('org.apache.tools.ant')
|
||||
assert f.endswith('ant.jar')
|
||||
ret = self.assert_in('Task', tip)
|
||||
self.assertEqual('', ret[2])
|
||||
|
||||
def test_imports3(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('os')
|
||||
assert f.endswith('os.py')
|
||||
ret = self.assert_in('path', tip)
|
||||
self.assertEqual('', ret[2])
|
||||
|
||||
def test_tip_on_string(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('string')
|
||||
self.assert_in('join', tip)
|
||||
self.assert_in('uppercase', tip)
|
||||
|
||||
def test_imports(self):
|
||||
tip = _pydev_jy_imports_tipper.generate_tip('__builtin__')[1]
|
||||
self.assert_in('tuple' , tip)
|
||||
self.assert_in('RuntimeError' , tip)
|
||||
self.assert_in('RuntimeWarning' , tip)
|
||||
|
||||
def test_imports5(self):
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('java.lang')
|
||||
if f is None:
|
||||
return # Not ok with java 9
|
||||
assert f.endswith('rt.jar')
|
||||
tup = self.assert_in('String' , tip)
|
||||
self.assertEqual(str(_pydev_jy_imports_tipper.TYPE_CLASS), tup[3])
|
||||
|
||||
tip = _pydev_jy_imports_tipper.generate_tip('java')[1]
|
||||
tup = self.assert_in('lang' , tip)
|
||||
self.assertEqual(str(_pydev_jy_imports_tipper.TYPE_IMPORT), tup[3])
|
||||
|
||||
tip = _pydev_jy_imports_tipper.generate_tip('java.lang.String')[1]
|
||||
tup = self.assert_in('indexOf' , tip)
|
||||
self.assertEqual(str(_pydev_jy_imports_tipper.TYPE_FUNCTION), tup[3])
|
||||
|
||||
tip = _pydev_jy_imports_tipper.generate_tip('java.lang.String')[1]
|
||||
tup = self.assert_in('charAt' , tip)
|
||||
self.assertEqual(str(_pydev_jy_imports_tipper.TYPE_FUNCTION), tup[3])
|
||||
self.assertEqual('(int)', tup[2])
|
||||
|
||||
tup = self.assert_in('format' , tip)
|
||||
self.assertEqual(str(_pydev_jy_imports_tipper.TYPE_FUNCTION), tup[3])
|
||||
self.assertEqual('(string, objectArray)', tup[2])
|
||||
self.assertTrue(tup[1].find('[Ljava.lang.Object;') == -1)
|
||||
|
||||
tup = self.assert_in('getBytes', tip)
|
||||
self.assertEqual(str(_pydev_jy_imports_tipper.TYPE_FUNCTION), tup[3])
|
||||
assert '[B' not in tup[1]
|
||||
assert 'byte[]' in tup[1]
|
||||
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('__builtin__.str')
|
||||
assert f is None or f.endswith('jython.jar') # Depends on jython version
|
||||
self.assert_in('find' , tip)
|
||||
|
||||
f, tip = _pydev_jy_imports_tipper.generate_tip('__builtin__.dict')
|
||||
assert f is None or f.endswith('jython.jar') # Depends on jython version
|
||||
self.assert_in('get' , tip)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not IS_JYTHON, reason='Jython related test')
|
||||
class TestSearch(unittest.TestCase):
|
||||
|
||||
def test_search_on_jython(self):
|
||||
assert _pydev_jy_imports_tipper.search_definition('os')[0][0].split(os.sep)[-1] in ('javaos.py', 'os.py')
|
||||
self.assertEqual(0, _pydev_jy_imports_tipper.search_definition('os')[0][1])
|
||||
|
||||
assert _pydev_jy_imports_tipper.search_definition('os.makedirs')[0][0].split(os.sep)[-1] in ('javaos.py', 'os.py')
|
||||
self.assertNotEqual(0, _pydev_jy_imports_tipper.search_definition('os.makedirs')[0][1])
|
||||
|
||||
# print _pydev_jy_imports_tipper.search_definition('os.makedirs')
|
||||
|
||||
|
||||
@pytest.mark.skipif(not IS_JYTHON, reason='Jython related test')
|
||||
class TestCompl(unittest.TestCase):
|
||||
|
||||
def test_getting_info_on_jython(self):
|
||||
|
||||
dbg('\n\n--------------------------- java')
|
||||
assert not ismethod(java)[0]
|
||||
assert not isclass(java)
|
||||
assert _pydev_jy_imports_tipper.ismodule(java)
|
||||
|
||||
dbg('\n\n--------------------------- java.lang')
|
||||
assert not ismethod(java.lang)[0]
|
||||
assert not isclass(java.lang)
|
||||
assert _pydev_jy_imports_tipper.ismodule(java.lang)
|
||||
|
||||
dbg('\n\n--------------------------- Method')
|
||||
assert not ismethod(Method)[0]
|
||||
assert isclass(Method)
|
||||
|
||||
dbg('\n\n--------------------------- System')
|
||||
assert not ismethod(System)[0]
|
||||
assert isclass(System)
|
||||
|
||||
dbg('\n\n--------------------------- String')
|
||||
assert not ismethod(System)[0]
|
||||
assert isclass(String)
|
||||
assert len(dir_obj(String)) > 10
|
||||
|
||||
dbg('\n\n--------------------------- arraycopy')
|
||||
isMet = ismethod(arraycopy)
|
||||
assert isMet[0]
|
||||
assert isMet[1][0].basic_as_str() == "function:arraycopy args=['java.lang.Object', 'int', 'java.lang.Object', 'int', 'int'], varargs=None, kwargs=None, docs:None"
|
||||
assert not isclass(arraycopy)
|
||||
|
||||
dbg('\n\n--------------------------- out')
|
||||
isMet = ismethod(out)
|
||||
assert not isMet[0]
|
||||
assert not isclass(out)
|
||||
|
||||
dbg('\n\n--------------------------- out.println')
|
||||
isMet = ismethod(out.println) # @UndefinedVariable
|
||||
assert isMet[0]
|
||||
assert len(isMet[1]) == 10
|
||||
self.assertEqual(isMet[1][0].basic_as_str(), "function:println args=[], varargs=None, kwargs=None, docs:None")
|
||||
assert isMet[1][1].basic_as_str() == "function:println args=['long'], varargs=None, kwargs=None, docs:None"
|
||||
assert not isclass(out.println) # @UndefinedVariable
|
||||
|
||||
dbg('\n\n--------------------------- str')
|
||||
isMet = ismethod(str)
|
||||
# the code below should work, but is failing on jython 22a1
|
||||
# assert isMet[0]
|
||||
# assert isMet[1][0].basic_as_str() == "function:str args=['org.python.core.PyObject'], varargs=None, kwargs=None, docs:None"
|
||||
assert not isclass(str)
|
||||
|
||||
def met1():
|
||||
a = 3
|
||||
return a
|
||||
|
||||
dbg('\n\n--------------------------- met1')
|
||||
isMet = ismethod(met1)
|
||||
assert isMet[0]
|
||||
assert isMet[1][0].basic_as_str() == "function:met1 args=[], varargs=None, kwargs=None, docs:None"
|
||||
assert not isclass(met1)
|
||||
|
||||
def met2(arg1, arg2, *vararg, **kwarg):
|
||||
'''docmet2'''
|
||||
|
||||
a = 1
|
||||
return a
|
||||
|
||||
dbg('\n\n--------------------------- met2')
|
||||
isMet = ismethod(met2)
|
||||
assert isMet[0]
|
||||
assert isMet[1][0].basic_as_str() == "function:met2 args=['arg1', 'arg2'], varargs=vararg, kwargs=kwarg, docs:docmet2"
|
||||
assert not isclass(met2)
|
||||
|
||||
# Run for jython in command line:
|
||||
|
||||
# On Windows:
|
||||
# c:/bin/jython2.7.0/bin/jython.exe -Dpython.path=jython_test_deps/ant.jar;jython_test_deps/junit.jar -m py.test tests/test_jysimpleTipper.py
|
||||
|
||||
# On Linux (different path separator for jars)
|
||||
# jython -Dpython.path=jython_test_deps/ant.jar:jython_test_deps/junit.jar -m py.test tests/test_jysimpleTipper.py
|
||||
@@ -0,0 +1,308 @@
|
||||
import sys
|
||||
import unittest
|
||||
import threading
|
||||
import os
|
||||
from _pydev_bundle.pydev_imports import SimpleXMLRPCServer
|
||||
from _pydev_bundle.pydev_localhost import get_localhost
|
||||
from _pydev_bundle.pydev_console_utils import StdIn
|
||||
import socket
|
||||
import time
|
||||
from _pydevd_bundle import pydevd_io
|
||||
import pytest
|
||||
|
||||
|
||||
def eq_(a, b):
|
||||
if a != b:
|
||||
raise AssertionError('%s != %s' % (a, b))
|
||||
|
||||
|
||||
try:
|
||||
from IPython import core
|
||||
has_ipython = True
|
||||
except:
|
||||
has_ipython = False
|
||||
|
||||
|
||||
@pytest.mark.skipif(not has_ipython, reason='IPython not available')
|
||||
class TestBase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
from _pydev_bundle.pydev_ipython_console_011 import get_pydev_frontend
|
||||
|
||||
# PyDevFrontEnd depends on singleton in IPython, so you
|
||||
# can't make multiple versions. So we reuse self.front_end for
|
||||
# all the tests
|
||||
self.front_end = get_pydev_frontend(get_localhost(), 0)
|
||||
|
||||
from pydev_ipython.inputhook import set_return_control_callback
|
||||
set_return_control_callback(lambda:True)
|
||||
self.front_end.clear_buffer()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def add_exec(self, code, expected_more=False):
|
||||
more = self.front_end.add_exec(code)
|
||||
eq_(expected_more, more)
|
||||
|
||||
def redirect_stdout(self):
|
||||
from IPython.utils import io
|
||||
|
||||
self.original_stdout = sys.stdout
|
||||
sys.stdout = io.stdout = pydevd_io.IOBuf()
|
||||
|
||||
def restore_stdout(self):
|
||||
from IPython.utils import io
|
||||
io.stdout = sys.stdout = self.original_stdout
|
||||
|
||||
|
||||
@pytest.mark.skipif(not has_ipython, reason='IPython not available')
|
||||
class TestPyDevFrontEnd(TestBase):
|
||||
|
||||
def testAddExec_1(self):
|
||||
self.add_exec('if True:', True)
|
||||
|
||||
def testAddExec_2(self):
|
||||
# Change: 'more' must now be controlled in the client side after the initial 'True' returned.
|
||||
self.add_exec('if True:\n testAddExec_a = 10\n', False)
|
||||
assert 'testAddExec_a' in self.front_end.get_namespace()
|
||||
|
||||
def testAddExec_3(self):
|
||||
assert 'testAddExec_x' not in self.front_end.get_namespace()
|
||||
self.add_exec('if True:\n testAddExec_x = 10\n\n')
|
||||
assert 'testAddExec_x' in self.front_end.get_namespace()
|
||||
eq_(self.front_end.get_namespace()['testAddExec_x'], 10)
|
||||
|
||||
def test_get_namespace(self):
|
||||
assert 'testGetNamespace_a' not in self.front_end.get_namespace()
|
||||
self.add_exec('testGetNamespace_a = 10')
|
||||
assert 'testGetNamespace_a' in self.front_end.get_namespace()
|
||||
eq_(self.front_end.get_namespace()['testGetNamespace_a'], 10)
|
||||
|
||||
def test_complete(self):
|
||||
unused_text, matches = self.front_end.complete('%')
|
||||
assert len(matches) > 1, 'at least one magic should appear in completions'
|
||||
|
||||
def test_complete_does_not_do_python_matches(self):
|
||||
# Test that IPython's completions do not do the things that
|
||||
# PyDev's completions will handle
|
||||
self.add_exec('testComplete_a = 5')
|
||||
self.add_exec('testComplete_b = 10')
|
||||
self.add_exec('testComplete_c = 15')
|
||||
unused_text, matches = self.front_end.complete('testComplete_')
|
||||
assert len(matches) == 0
|
||||
|
||||
def testGetCompletions_1(self):
|
||||
# Test the merged completions include the standard completions
|
||||
self.add_exec('testComplete_a = 5')
|
||||
self.add_exec('testComplete_b = 10')
|
||||
self.add_exec('testComplete_c = 15')
|
||||
res = self.front_end.getCompletions('testComplete_', 'testComplete_')
|
||||
matches = [f[0] for f in res]
|
||||
assert len(matches) == 3
|
||||
eq_(set(['testComplete_a', 'testComplete_b', 'testComplete_c']), set(matches))
|
||||
|
||||
def testGetCompletions_2(self):
|
||||
# Test that we get IPython completions in results
|
||||
# we do this by checking kw completion which PyDev does
|
||||
# not do by default
|
||||
self.add_exec('def ccc(ABC=123): pass')
|
||||
res = self.front_end.getCompletions('ccc(', '')
|
||||
matches = [f[0] for f in res]
|
||||
assert 'ABC=' in matches
|
||||
|
||||
def testGetCompletions_3(self):
|
||||
# Test that magics return IPYTHON magic as type
|
||||
res = self.front_end.getCompletions('%cd', '%cd')
|
||||
assert len(res) == 1
|
||||
eq_(res[0][3], '12') # '12' == IToken.TYPE_IPYTHON_MAGIC
|
||||
assert len(res[0][1]) > 100, 'docstring for %cd should be a reasonably long string'
|
||||
|
||||
|
||||
@pytest.mark.skipif(not has_ipython, reason='IPython not available')
|
||||
class TestRunningCode(TestBase):
|
||||
|
||||
def test_print(self):
|
||||
self.redirect_stdout()
|
||||
try:
|
||||
self.add_exec('print("output")')
|
||||
eq_(sys.stdout.getvalue(), 'output\n')
|
||||
finally:
|
||||
self.restore_stdout()
|
||||
|
||||
def testQuestionMark_1(self):
|
||||
self.redirect_stdout()
|
||||
try:
|
||||
self.add_exec('?')
|
||||
found = sys.stdout.getvalue()
|
||||
if len(found) < 1000:
|
||||
raise AssertionError('Expected IPython help to be big. Found: %s' % (found,))
|
||||
finally:
|
||||
self.restore_stdout()
|
||||
|
||||
def testQuestionMark_2(self):
|
||||
self.redirect_stdout()
|
||||
try:
|
||||
self.add_exec('int?')
|
||||
found = sys.stdout.getvalue()
|
||||
if 'Convert' not in found:
|
||||
raise AssertionError('Expected to find "Convert" in %s' % (found,))
|
||||
finally:
|
||||
self.restore_stdout()
|
||||
|
||||
def test_gui(self):
|
||||
try:
|
||||
import Tkinter
|
||||
except:
|
||||
return
|
||||
else:
|
||||
from pydev_ipython.inputhook import get_inputhook
|
||||
assert get_inputhook() is None
|
||||
self.add_exec('%gui tk')
|
||||
# we can't test the GUI works here because we aren't connected to XML-RPC so
|
||||
# nowhere for hook to run
|
||||
assert get_inputhook() is not None
|
||||
self.add_exec('%gui none')
|
||||
assert get_inputhook() is None
|
||||
|
||||
def test_history(self):
|
||||
''' Make sure commands are added to IPython's history '''
|
||||
self.redirect_stdout()
|
||||
try:
|
||||
self.add_exec('a=1')
|
||||
self.add_exec('b=2')
|
||||
_ih = self.front_end.get_namespace()['_ih']
|
||||
eq_(_ih[-1], 'b=2')
|
||||
eq_(_ih[-2], 'a=1')
|
||||
|
||||
self.add_exec('history')
|
||||
hist = sys.stdout.getvalue().split('\n')
|
||||
eq_(hist[-1], '')
|
||||
eq_(hist[-2], 'history')
|
||||
eq_(hist[-3], 'b=2')
|
||||
eq_(hist[-4], 'a=1')
|
||||
finally:
|
||||
self.restore_stdout()
|
||||
|
||||
def test_edit(self):
|
||||
''' Make sure we can issue an edit command'''
|
||||
if os.environ.get('TRAVIS') == 'true':
|
||||
# This test is too flaky on travis.
|
||||
return
|
||||
|
||||
from _pydev_bundle.pydev_ipython_console_011 import get_pydev_frontend
|
||||
|
||||
called_RequestInput = [False]
|
||||
called_IPythonEditor = [False]
|
||||
|
||||
def start_client_thread(client_port):
|
||||
|
||||
class ClientThread(threading.Thread):
|
||||
|
||||
def __init__(self, client_port):
|
||||
threading.Thread.__init__(self)
|
||||
self.client_port = client_port
|
||||
|
||||
def run(self):
|
||||
|
||||
class HandleRequestInput:
|
||||
|
||||
def RequestInput(self):
|
||||
called_RequestInput[0] = True
|
||||
return '\n'
|
||||
|
||||
def IPythonEditor(self, name, line):
|
||||
called_IPythonEditor[0] = (name, line)
|
||||
return True
|
||||
|
||||
handle_request_input = HandleRequestInput()
|
||||
|
||||
from _pydev_bundle import pydev_localhost
|
||||
self.client_server = client_server = SimpleXMLRPCServer(
|
||||
(pydev_localhost.get_localhost(), self.client_port), logRequests=False)
|
||||
client_server.register_function(handle_request_input.RequestInput)
|
||||
client_server.register_function(handle_request_input.IPythonEditor)
|
||||
client_server.serve_forever()
|
||||
|
||||
def shutdown(self):
|
||||
return
|
||||
self.client_server.shutdown()
|
||||
|
||||
client_thread = ClientThread(client_port)
|
||||
client_thread.daemon = True
|
||||
client_thread.start()
|
||||
return client_thread
|
||||
|
||||
# PyDevFrontEnd depends on singleton in IPython, so you
|
||||
# can't make multiple versions. So we reuse self.front_end for
|
||||
# all the tests
|
||||
s = socket.socket()
|
||||
s.bind(('', 0))
|
||||
self.client_port = client_port = s.getsockname()[1]
|
||||
s.close()
|
||||
self.front_end = get_pydev_frontend(get_localhost(), client_port)
|
||||
|
||||
client_thread = start_client_thread(self.client_port)
|
||||
orig_stdin = sys.stdin
|
||||
sys.stdin = StdIn(self, get_localhost(), self.client_port)
|
||||
try:
|
||||
filename = 'made_up_file.py'
|
||||
self.add_exec('%edit ' + filename)
|
||||
|
||||
for i in range(10):
|
||||
if called_IPythonEditor[0] == (os.path.abspath(filename), '0'):
|
||||
break
|
||||
time.sleep(.1)
|
||||
|
||||
if not called_IPythonEditor[0]:
|
||||
# File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/interactiveshell.py", line 2883, in run_code
|
||||
# exec(code_obj, self.user_global_ns, self.user_ns)
|
||||
# File "<ipython-input-15-09583ca3bce1>", line 1, in <module>
|
||||
# get_ipython().magic('edit made_up_file.py')
|
||||
# File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/interactiveshell.py", line 2205, in magic
|
||||
# return self.run_line_magic(magic_name, magic_arg_s)
|
||||
# File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/interactiveshell.py", line 2126, in run_line_magic
|
||||
# result = fn(*args,**kwargs)
|
||||
# File "<string>", line 2, in edit
|
||||
# File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/magic.py", line 193, in <lambda>
|
||||
# call = lambda f, *a, **k: f(*a, **k)
|
||||
# File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/magics/code.py", line 662, in edit
|
||||
# self.shell.hooks.editor(filename,lineno)
|
||||
# File "/home/travis/build/fabioz/PyDev.Debugger/pydev_ipython_console_011.py", line 70, in call_editor
|
||||
# server.IPythonEditor(filename, str(line))
|
||||
# File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1090, in __call__
|
||||
# return self.__send(self.__name, args)
|
||||
# File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1419, in __request
|
||||
# verbose=self.__verbose
|
||||
# File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1132, in request
|
||||
# return self.single_request(host, handler, request_body, verbose)
|
||||
# File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1143, in single_request
|
||||
# http_conn = self.send_request(host, handler, request_body, verbose)
|
||||
# File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1255, in send_request
|
||||
# self.send_content(connection, request_body)
|
||||
# File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1285, in send_content
|
||||
# connection.endheaders(request_body)
|
||||
# File "/home/travis/miniconda/lib/python3.3/http/client.py", line 1061, in endheaders
|
||||
# self._send_output(message_body)
|
||||
# File "/home/travis/miniconda/lib/python3.3/http/client.py", line 906, in _send_output
|
||||
# self.send(msg)
|
||||
# File "/home/travis/miniconda/lib/python3.3/http/client.py", line 844, in send
|
||||
# self.connect()
|
||||
# File "/home/travis/miniconda/lib/python3.3/http/client.py", line 822, in connect
|
||||
# self.timeout, self.source_address)
|
||||
# File "/home/travis/miniconda/lib/python3.3/socket.py", line 435, in create_connection
|
||||
# raise err
|
||||
# File "/home/travis/miniconda/lib/python3.3/socket.py", line 426, in create_connection
|
||||
# sock.connect(sa)
|
||||
# ConnectionRefusedError: [Errno 111] Connection refused
|
||||
|
||||
# I.e.: just warn that the test failing, don't actually fail.
|
||||
sys.stderr.write('Test failed: this test is brittle in travis because sometimes the connection is refused (as above) and we do not have a callback.\n')
|
||||
return
|
||||
|
||||
eq_(called_IPythonEditor[0], (os.path.abspath(filename), '0'))
|
||||
assert called_RequestInput[0], "Make sure the 'wait' parameter has been respected"
|
||||
finally:
|
||||
sys.stdin = orig_stdin
|
||||
client_thread.shutdown()
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
import threading
|
||||
import unittest
|
||||
import sys
|
||||
import pydevconsole
|
||||
from _pydev_bundle.pydev_imports import xmlrpclib, SimpleXMLRPCServer
|
||||
from _pydevd_bundle import pydevd_io
|
||||
from contextlib import contextmanager
|
||||
import pytest
|
||||
|
||||
try:
|
||||
from ast import PyCF_ALLOW_TOP_LEVEL_AWAIT # @UnusedImport
|
||||
CAN_EVALUATE_TOP_LEVEL_ASYNC = True
|
||||
except:
|
||||
CAN_EVALUATE_TOP_LEVEL_ASYNC = False
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
# Test
|
||||
#=======================================================================================================================
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
@contextmanager
|
||||
def interpreter(self):
|
||||
self.original_stdout = sys.stdout
|
||||
self.original_stderr = sys.stderr
|
||||
sys.stdout = pydevd_io.IOBuf()
|
||||
sys.stderr = pydevd_io.IOBuf()
|
||||
try:
|
||||
sys.stdout.encoding = sys.stdin.encoding
|
||||
sys.stderr.encoding = sys.stdin.encoding
|
||||
except AttributeError:
|
||||
# In Python 3 encoding is not writable (whereas in Python 2 it doesn't exist).
|
||||
pass
|
||||
|
||||
try:
|
||||
client_port, _server_port = self.get_free_addresses()
|
||||
client_thread = self.start_client_thread(client_port) # @UnusedVariable
|
||||
import time
|
||||
time.sleep(.3) # let's give it some time to start the threads
|
||||
|
||||
from _pydev_bundle import pydev_localhost
|
||||
interpreter = pydevconsole.InterpreterInterface(pydev_localhost.get_localhost(), client_port, threading.current_thread())
|
||||
yield interpreter
|
||||
except:
|
||||
# if there's some error, print the output to the actual output.
|
||||
self.original_stdout.write(sys.stdout.getvalue())
|
||||
self.original_stderr.write(sys.stderr.getvalue())
|
||||
raise
|
||||
finally:
|
||||
sys.stderr = self.original_stderr
|
||||
sys.stdout = self.original_stdout
|
||||
|
||||
def test_console_hello(self):
|
||||
with self.interpreter() as interpreter:
|
||||
(result,) = interpreter.hello("Hello pydevconsole")
|
||||
self.assertEqual(result, "Hello eclipse")
|
||||
|
||||
@pytest.mark.skipif(not CAN_EVALUATE_TOP_LEVEL_ASYNC, reason='Requires top-level async.')
|
||||
def test_console_async(self):
|
||||
with self.interpreter() as interpreter:
|
||||
from _pydev_bundle.pydev_console_utils import CodeFragment
|
||||
more = interpreter.add_exec(CodeFragment('''
|
||||
async def async_func(a):
|
||||
return a
|
||||
'''))
|
||||
assert not more
|
||||
assert not sys.stderr.getvalue()
|
||||
assert not sys.stdout.getvalue()
|
||||
|
||||
more = interpreter.add_exec(CodeFragment('''x = await async_func(1111)'''))
|
||||
assert not more
|
||||
assert not sys.stderr.getvalue()
|
||||
assert not sys.stdout.getvalue()
|
||||
|
||||
more = interpreter.add_exec(CodeFragment('''print(x)'''))
|
||||
assert not more
|
||||
assert not sys.stderr.getvalue()
|
||||
assert '1111' in sys.stdout.getvalue()
|
||||
|
||||
def test_console_requests(self):
|
||||
with self.interpreter() as interpreter:
|
||||
from _pydev_bundle.pydev_console_utils import CodeFragment
|
||||
interpreter.add_exec(CodeFragment('class Foo:\n CONSTANT=1\n'))
|
||||
interpreter.add_exec(CodeFragment('foo=Foo()'))
|
||||
interpreter.add_exec(CodeFragment('foo.__doc__=None'))
|
||||
interpreter.add_exec(CodeFragment('val = input()'))
|
||||
interpreter.add_exec(CodeFragment('50'))
|
||||
interpreter.add_exec(CodeFragment('print (val)'))
|
||||
found = sys.stdout.getvalue().split()
|
||||
try:
|
||||
self.assertEqual(['50', 'input_request'], found)
|
||||
except:
|
||||
try:
|
||||
self.assertEqual(['input_request'], found) # IPython
|
||||
except:
|
||||
self.assertEqual([u'50', u'input_request'], found[1:]) # IPython 5.1
|
||||
self.assertTrue(found[0].startswith(u'Out'))
|
||||
|
||||
comps = interpreter.getCompletions('foo.', 'foo.')
|
||||
self.assertTrue(
|
||||
('CONSTANT', '', '', '3') in comps or ('CONSTANT', '', '', '4') in comps, \
|
||||
'Found: %s' % comps
|
||||
)
|
||||
|
||||
comps = interpreter.getCompletions('"".', '"".')
|
||||
self.assertTrue(
|
||||
('__add__', 'x.__add__(y) <==> x+y', '', '3') in comps or
|
||||
('__add__', '', '', '4') in comps or
|
||||
('__add__', 'x.__add__(y) <==> x+y\r\nx.__add__(y) <==> x+y', '()', '2') in comps or
|
||||
('__add__', 'x.\n__add__(y) <==> x+yx.\n__add__(y) <==> x+y', '()', '2'),
|
||||
'Did not find __add__ in : %s' % (comps,)
|
||||
)
|
||||
|
||||
completions = interpreter.getCompletions('', '')
|
||||
for c in completions:
|
||||
if c[0] == 'AssertionError':
|
||||
break
|
||||
else:
|
||||
self.fail('Could not find AssertionError')
|
||||
|
||||
completions = interpreter.getCompletions('Assert', 'Assert')
|
||||
for c in completions:
|
||||
if c[0] == 'RuntimeError':
|
||||
self.fail('Did not expect to find RuntimeError there')
|
||||
|
||||
assert ('__doc__', None, '', '3') not in interpreter.getCompletions('foo.CO', 'foo.')
|
||||
|
||||
comps = interpreter.getCompletions('va', 'va')
|
||||
assert ('val', '', '', '3') in comps or ('val', '', '', '4') in comps
|
||||
|
||||
interpreter.add_exec(CodeFragment('s = "mystring"'))
|
||||
|
||||
desc = interpreter.getDescription('val')
|
||||
self.assertTrue(desc.find('str(object) -> string') >= 0 or
|
||||
desc == "'input_request'" or
|
||||
desc.find('str(string[, encoding[, errors]]) -> str') >= 0 or
|
||||
desc.find('str(Char* value)') >= 0 or
|
||||
desc.find('str(object=\'\') -> string') >= 0 or
|
||||
desc.find('str(value: Char*)') >= 0 or
|
||||
desc.find('str(object=\'\') -> str') >= 0 or
|
||||
desc.find('The most base type') >= 0 # Jython 2.7 is providing this :P
|
||||
,
|
||||
'Could not find what was needed in %s' % desc)
|
||||
|
||||
desc = interpreter.getDescription('val.join')
|
||||
self.assertTrue(desc.find('S.join(sequence) -> string') >= 0 or
|
||||
desc.find('S.join(sequence) -> str') >= 0 or
|
||||
desc.find('S.join(iterable) -> string') >= 0 or
|
||||
desc == "<builtin method 'join'>" or
|
||||
desc == "<built-in method join of str object>" or
|
||||
desc.find('str join(str self, list sequence)') >= 0 or
|
||||
desc.find('S.join(iterable) -> str') >= 0 or
|
||||
desc.find('join(self: str, sequence: list) -> str') >= 0 or
|
||||
desc.find('Concatenate any number of strings.') >= 0 or
|
||||
desc.find('bound method str.join') >= 0, # PyPy
|
||||
"Could not recognize: %s" % (desc,))
|
||||
|
||||
def start_client_thread(self, client_port):
|
||||
|
||||
class ClientThread(threading.Thread):
|
||||
|
||||
def __init__(self, client_port):
|
||||
threading.Thread.__init__(self)
|
||||
self.client_port = client_port
|
||||
|
||||
def run(self):
|
||||
|
||||
class HandleRequestInput:
|
||||
|
||||
def RequestInput(self):
|
||||
client_thread.requested_input = True
|
||||
return 'input_request'
|
||||
|
||||
def NotifyFinished(self, *args, **kwargs):
|
||||
client_thread.notified_finished += 1
|
||||
return 1
|
||||
|
||||
handle_request_input = HandleRequestInput()
|
||||
|
||||
from _pydev_bundle import pydev_localhost
|
||||
client_server = SimpleXMLRPCServer((pydev_localhost.get_localhost(), self.client_port), logRequests=False)
|
||||
client_server.register_function(handle_request_input.RequestInput)
|
||||
client_server.register_function(handle_request_input.NotifyFinished)
|
||||
client_server.serve_forever()
|
||||
|
||||
client_thread = ClientThread(client_port)
|
||||
client_thread.requested_input = False
|
||||
client_thread.notified_finished = 0
|
||||
client_thread.daemon = True
|
||||
client_thread.start()
|
||||
return client_thread
|
||||
|
||||
def start_debugger_server_thread(self, debugger_port, socket_code):
|
||||
|
||||
class DebuggerServerThread(threading.Thread):
|
||||
|
||||
def __init__(self, debugger_port, socket_code):
|
||||
threading.Thread.__init__(self)
|
||||
self.debugger_port = debugger_port
|
||||
self.socket_code = socket_code
|
||||
|
||||
def run(self):
|
||||
import socket
|
||||
s = socket.socket()
|
||||
s.bind(('', debugger_port))
|
||||
s.listen(1)
|
||||
socket, unused_addr = s.accept()
|
||||
socket_code(socket)
|
||||
|
||||
debugger_thread = DebuggerServerThread(debugger_port, socket_code)
|
||||
debugger_thread.daemon = True
|
||||
debugger_thread.start()
|
||||
return debugger_thread
|
||||
|
||||
def get_free_addresses(self):
|
||||
from _pydev_bundle.pydev_localhost import get_socket_names
|
||||
socket_names = get_socket_names(2, True)
|
||||
port0 = socket_names[0][1]
|
||||
port1 = socket_names[1][1]
|
||||
|
||||
assert port0 != port1
|
||||
assert port0 > 0
|
||||
assert port1 > 0
|
||||
|
||||
return port0, port1
|
||||
|
||||
def test_server(self):
|
||||
self.original_stdout = sys.stdout
|
||||
sys.stdout = pydevd_io.IOBuf()
|
||||
try:
|
||||
client_port, server_port = self.get_free_addresses()
|
||||
|
||||
class ServerThread(threading.Thread):
|
||||
|
||||
def __init__(self, client_port, server_port):
|
||||
threading.Thread.__init__(self)
|
||||
self.client_port = client_port
|
||||
self.server_port = server_port
|
||||
|
||||
def run(self):
|
||||
from _pydev_bundle import pydev_localhost
|
||||
pydevconsole.start_server(pydev_localhost.get_localhost(), self.server_port, self.client_port)
|
||||
|
||||
server_thread = ServerThread(client_port, server_port)
|
||||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
client_thread = self.start_client_thread(client_port) # @UnusedVariable
|
||||
|
||||
import time
|
||||
time.sleep(.3) # let's give it some time to start the threads
|
||||
sys.stdout = pydevd_io.IOBuf()
|
||||
|
||||
from _pydev_bundle import pydev_localhost
|
||||
server = xmlrpclib.Server('http://%s:%s' % (pydev_localhost.get_localhost(), server_port))
|
||||
server.execLine('class Foo:')
|
||||
server.execLine(' pass')
|
||||
server.execLine('')
|
||||
server.execLine('foo = Foo()')
|
||||
server.execLine('a = input()')
|
||||
server.execLine('print (a)')
|
||||
initial = time.time()
|
||||
while not client_thread.requested_input:
|
||||
if time.time() - initial > 2:
|
||||
raise AssertionError('Did not get the return asked before the timeout.')
|
||||
time.sleep(.1)
|
||||
|
||||
found = sys.stdout.getvalue()
|
||||
while ['input_request'] != found.split():
|
||||
found += sys.stdout.getvalue()
|
||||
if time.time() - initial > 2:
|
||||
break
|
||||
time.sleep(.1)
|
||||
self.assertEqual(['input_request'], found.split())
|
||||
finally:
|
||||
sys.stdout = self.original_stdout
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import sys
|
||||
from _pydev_bundle._pydev_saved_modules import thread
|
||||
import pycompletionserver
|
||||
import socket
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
start_new_thread = thread.start_new_thread
|
||||
|
||||
BUILTIN_MOD = 'builtins'
|
||||
|
||||
|
||||
def send(s, msg):
|
||||
s.send(bytearray(msg, 'utf-8'))
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCPython(unittest.TestCase):
|
||||
|
||||
def test_message(self):
|
||||
t = pycompletionserver.CompletionServer(0)
|
||||
|
||||
l = []
|
||||
l.append(('Def', 'description' , 'args'))
|
||||
l.append(('Def1', 'description1', 'args1'))
|
||||
l.append(('Def2', 'description2', 'args2'))
|
||||
|
||||
msg = t.processor.format_completion_message(None, l)
|
||||
|
||||
self.assertEqual('@@COMPLETIONS(None,(Def,description,args),(Def1,description1,args1),(Def2,description2,args2))END@@', msg)
|
||||
l = []
|
||||
l.append(('Def', 'desc,,r,,i()ption', ''))
|
||||
l.append(('Def(1', 'descriptio(n1', ''))
|
||||
l.append(('De,f)2', 'de,s,c,ription2', ''))
|
||||
msg = t.processor.format_completion_message(None, l)
|
||||
self.assertEqual('@@COMPLETIONS(None,(Def,desc%2C%2Cr%2C%2Ci%28%29ption, ),(Def%281,descriptio%28n1, ),(De%2Cf%292,de%2Cs%2Cc%2Cription2, ))END@@', msg)
|
||||
|
||||
def create_connections(self):
|
||||
'''
|
||||
Creates the connections needed for testing.
|
||||
'''
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.bind((pycompletionserver.HOST, 0))
|
||||
server.listen(1) # socket to receive messages.
|
||||
|
||||
t = pycompletionserver.CompletionServer(server.getsockname()[1])
|
||||
t.exit_process_on_kill = False
|
||||
start_new_thread(t.run, ())
|
||||
|
||||
s, _addr = server.accept()
|
||||
|
||||
return t, s
|
||||
|
||||
def read_msg(self):
|
||||
finish = False
|
||||
msg = ''
|
||||
while finish == False:
|
||||
m = self.socket.recv(1024 * 4)
|
||||
m = m.decode('utf-8')
|
||||
if m.startswith('@@PROCESSING'):
|
||||
sys.stdout.write('Status msg: %s\n' % (msg,))
|
||||
else:
|
||||
msg += m
|
||||
|
||||
if msg.find('END@@') != -1:
|
||||
finish = True
|
||||
|
||||
return msg
|
||||
|
||||
def test_completion_sockets_and_messages(self):
|
||||
t, socket = self.create_connections()
|
||||
self.socket = socket
|
||||
|
||||
try:
|
||||
# now that we have the connections all set up, check the code completion messages.
|
||||
msg = quote_plus('math')
|
||||
send(socket, '@@IMPORTS:%sEND@@' % msg) # math completions
|
||||
completions = self.read_msg()
|
||||
# print_ unquote_plus(completions)
|
||||
|
||||
# math is a builtin and because of that, it starts with None as a file
|
||||
start = '@@COMPLETIONS(None,(__doc__,'
|
||||
start_2 = '@@COMPLETIONS(None,(__name__,'
|
||||
if ('/math.so,' in completions or
|
||||
'/math.cpython-33m.so,' in completions or
|
||||
'/math.cpython-34m.so,' in completions or
|
||||
'math.cpython-35m' in completions or
|
||||
'math.cpython-36m' in completions or
|
||||
'math.cpython-37m' in completions or
|
||||
'math.cpython-38' in completions or
|
||||
'math.cpython-39' in completions or
|
||||
'math.cpython-310' in completions or
|
||||
'math.cpython-311' in completions
|
||||
):
|
||||
return
|
||||
self.assertTrue(completions.startswith(start) or completions.startswith(start_2), '%s DOESNT START WITH %s' % (completions, (start, start_2)))
|
||||
|
||||
self.assertTrue('@@COMPLETIONS' in completions)
|
||||
self.assertTrue('END@@' in completions)
|
||||
|
||||
# now, test i
|
||||
msg = quote_plus('%s.list' % BUILTIN_MOD)
|
||||
send(socket, "@@IMPORTS:%s\nEND@@" % msg)
|
||||
found = self.read_msg()
|
||||
self.assertTrue('sort' in found, 'Could not find sort in: %s' % (found,))
|
||||
|
||||
# now, test search
|
||||
msg = quote_plus('inspect.ismodule')
|
||||
send(socket, '@@SEARCH%sEND@@' % msg) # math completions
|
||||
found = self.read_msg()
|
||||
self.assertTrue('inspect.py' in found)
|
||||
for i in range(33, 100):
|
||||
if str(i) in found:
|
||||
break
|
||||
else:
|
||||
self.fail('Could not find the ismodule line in %s' % (found,))
|
||||
|
||||
# now, test search
|
||||
msg = quote_plus('inspect.CO_NEWLOCALS')
|
||||
send(socket, '@@SEARCH%sEND@@' % msg) # math completions
|
||||
found = self.read_msg()
|
||||
self.assertTrue('inspect.py' in found)
|
||||
self.assertTrue('CO_NEWLOCALS' in found)
|
||||
|
||||
# now, test search
|
||||
msg = quote_plus('inspect.BlockFinder.tokeneater')
|
||||
send(socket, '@@SEARCH%sEND@@' % msg)
|
||||
found = self.read_msg()
|
||||
self.assertTrue('inspect.py' in found)
|
||||
# self.assertTrue('CO_NEWLOCALS' in found)
|
||||
|
||||
# reload modules test
|
||||
# send(socket, '@@RELOAD_MODULES_END@@')
|
||||
# ok = self.read_msg()
|
||||
# self.assertEqual('@@MSG_OK_END@@' , ok)
|
||||
# this test is not executed because it breaks our current enviroment.
|
||||
|
||||
finally:
|
||||
try:
|
||||
sys.stdout.write('succedded...sending kill msg\n')
|
||||
self.send_kill_msg(socket)
|
||||
|
||||
# while not hasattr(t, 'ended'):
|
||||
# pass #wait until it receives the message and quits.
|
||||
|
||||
socket.close()
|
||||
self.socket.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
def send_kill_msg(self, socket):
|
||||
socket.send(pycompletionserver.MSG_KILL_SERVER)
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
'''
|
||||
@author Fabio Zadrozny
|
||||
'''
|
||||
from _pydev_bundle import _pydev_imports_tipper
|
||||
import inspect
|
||||
import pytest
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
try:
|
||||
import __builtin__ # @UnusedImport
|
||||
BUILTIN_MOD = '__builtin__'
|
||||
except ImportError:
|
||||
BUILTIN_MOD = 'builtins'
|
||||
|
||||
IS_JYTHON = sys.platform.find('java') != -1
|
||||
|
||||
HAS_WX = False
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='CPython related test')
|
||||
class TestCPython(unittest.TestCase):
|
||||
|
||||
def p(self, t):
|
||||
for a in t:
|
||||
sys.stdout.write('%s\n' % (a,))
|
||||
|
||||
def test_imports3(self):
|
||||
tip = _pydev_imports_tipper.generate_tip('os')
|
||||
ret = self.assert_in('path', tip)
|
||||
self.assertEqual('', ret[2])
|
||||
|
||||
def test_imports2(self):
|
||||
try:
|
||||
tip = _pydev_imports_tipper.generate_tip('OpenGL.GLUT')
|
||||
self.assert_in('glutDisplayFunc', tip)
|
||||
self.assert_in('glutInitDisplayMode', tip)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def test_imports4(self):
|
||||
try:
|
||||
tip = _pydev_imports_tipper.generate_tip('mx.DateTime.mxDateTime.mxDateTime')
|
||||
self.assert_in('now', tip)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def test_imports5(self):
|
||||
tip = _pydev_imports_tipper.generate_tip('%s.list' % BUILTIN_MOD)
|
||||
s = self.assert_in('sort', tip)
|
||||
self.check_args(
|
||||
s,
|
||||
'(cmp=None, key=None, reverse=False)',
|
||||
'(self, object cmp, object key, bool reverse)',
|
||||
'(self, cmp: object, key: object, reverse: bool)',
|
||||
'(key=None, reverse=False)',
|
||||
'(self, key=None, reverse=False)',
|
||||
'(self, cmp, key, reverse)',
|
||||
'(self, key, reverse)',
|
||||
)
|
||||
|
||||
def test_imports2a(self):
|
||||
tips = _pydev_imports_tipper.generate_tip('%s.RuntimeError' % BUILTIN_MOD)
|
||||
self.assert_in('__doc__', tips)
|
||||
|
||||
def test_imports2b(self):
|
||||
try:
|
||||
file
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
tips = _pydev_imports_tipper.generate_tip('%s' % BUILTIN_MOD)
|
||||
t = self.assert_in('file' , tips)
|
||||
self.assertTrue('->' in t[1].strip() or 'file' in t[1])
|
||||
|
||||
def test_imports2c(self):
|
||||
try:
|
||||
file # file is not available on py 3
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
tips = _pydev_imports_tipper.generate_tip('%s.file' % BUILTIN_MOD)
|
||||
t = self.assert_in('readlines' , tips)
|
||||
self.assertTrue('->' in t[1] or 'sizehint' in t[1])
|
||||
|
||||
def test_imports(self):
|
||||
'''
|
||||
You can print_ the results to check...
|
||||
'''
|
||||
if HAS_WX:
|
||||
tip = _pydev_imports_tipper.generate_tip('wxPython.wx')
|
||||
self.assert_in('wxApp' , tip)
|
||||
|
||||
tip = _pydev_imports_tipper.generate_tip('wxPython.wx.wxApp')
|
||||
|
||||
try:
|
||||
tip = _pydev_imports_tipper.generate_tip('qt')
|
||||
self.assert_in('QWidget' , tip)
|
||||
self.assert_in('QDialog' , tip)
|
||||
|
||||
tip = _pydev_imports_tipper.generate_tip('qt.QWidget')
|
||||
self.assert_in('rect' , tip)
|
||||
self.assert_in('rect' , tip)
|
||||
self.assert_in('AltButton' , tip)
|
||||
|
||||
tip = _pydev_imports_tipper.generate_tip('qt.QWidget.AltButton')
|
||||
self.assert_in('__xor__' , tip)
|
||||
|
||||
tip = _pydev_imports_tipper.generate_tip('qt.QWidget.AltButton.__xor__')
|
||||
self.assert_in('__class__' , tip)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
tip = _pydev_imports_tipper.generate_tip(BUILTIN_MOD)
|
||||
# for t in tip[1]:
|
||||
# print_ t
|
||||
self.assert_in('object' , tip)
|
||||
self.assert_in('tuple' , tip)
|
||||
self.assert_in('list' , tip)
|
||||
self.assert_in('RuntimeError' , tip)
|
||||
self.assert_in('RuntimeWarning' , tip)
|
||||
|
||||
# Remove cmp as it's not available on py 3
|
||||
# t = self.assert_in('cmp' , tip)
|
||||
# self.check_args(t, '(x, y)', '(object x, object y)', '(x: object, y: object)') #args
|
||||
|
||||
t = self.assert_in('isinstance' , tip)
|
||||
self.check_args(
|
||||
t,
|
||||
'(object, class_or_type_or_tuple)',
|
||||
'(object o, type typeinfo)',
|
||||
'(o: object, typeinfo: type)',
|
||||
'(obj, class_or_tuple)',
|
||||
'(obj, klass_or_tuple)',
|
||||
) # args
|
||||
|
||||
t = self.assert_in('compile' , tip)
|
||||
self.check_args(
|
||||
t,
|
||||
'(source, filename, mode)',
|
||||
'()',
|
||||
'(o: object, name: str, val: object)',
|
||||
'(source, filename, mode, flags, dont_inherit, optimize)',
|
||||
'(source, filename, mode, flags, dont_inherit)',
|
||||
'(source, filename, mode, flags, dont_inherit, optimize, _feature_version=-1)'
|
||||
) # args
|
||||
|
||||
t = self.assert_in('setattr' , tip)
|
||||
self.check_args(
|
||||
t,
|
||||
'(object, name, value)',
|
||||
'(object o, str name, object val)',
|
||||
'(o: object, name: str, val: object)',
|
||||
'(obj, name, value)',
|
||||
'(object, name, val)',
|
||||
) # args
|
||||
|
||||
try:
|
||||
import compiler
|
||||
compiler_module = 'compiler'
|
||||
except ImportError:
|
||||
try:
|
||||
import ast
|
||||
compiler_module = 'ast'
|
||||
except ImportError:
|
||||
compiler_module = None
|
||||
|
||||
if compiler_module is not None: # Not available in iron python
|
||||
tip = _pydev_imports_tipper.generate_tip(compiler_module)
|
||||
if compiler_module == 'compiler':
|
||||
self.assert_args('parse', '(buf, mode)', tip)
|
||||
self.assert_args('walk', '(tree, visitor, walker, verbose)', tip)
|
||||
self.assert_in('parseFile' , tip)
|
||||
else:
|
||||
self.assert_args('parse', [
|
||||
'(source, filename, mode)',
|
||||
'(source, filename, mode, type_comments=False, feature_version=None)'
|
||||
], tip
|
||||
)
|
||||
self.assert_args('walk', '(node)', tip)
|
||||
self.assert_in('parse' , tip)
|
||||
|
||||
def check_args(self, t, *expected):
|
||||
for x in expected:
|
||||
if x == t[2]:
|
||||
return
|
||||
self.fail('Found: %s. Expected: %s' % (t[2], expected))
|
||||
|
||||
def assert_args(self, tok, args, tips):
|
||||
if not isinstance(args, (list, tuple)):
|
||||
args = (args,)
|
||||
|
||||
for a in tips[1]:
|
||||
if tok == a[0]:
|
||||
for arg in args:
|
||||
if arg == a[2]:
|
||||
return
|
||||
raise AssertionError('%s not in %s', a[2], args)
|
||||
|
||||
raise AssertionError('%s not in %s', tok, tips)
|
||||
|
||||
def assert_in(self, tok, tips):
|
||||
for a in tips[1]:
|
||||
if tok == a[0]:
|
||||
return a
|
||||
raise AssertionError('%s not in %s' % (tok, tips))
|
||||
|
||||
def test_search(self):
|
||||
s = _pydev_imports_tipper.search_definition('inspect.ismodule')
|
||||
(f, line, col), foundAs = s
|
||||
self.assertTrue(line > 0)
|
||||
|
||||
def test_dot_net_libraries(self):
|
||||
if sys.platform == 'cli':
|
||||
tip = _pydev_imports_tipper.generate_tip('System.Drawing')
|
||||
self.assert_in('Brushes' , tip)
|
||||
|
||||
tip = _pydev_imports_tipper.generate_tip('System.Drawing.Brushes')
|
||||
self.assert_in('Aqua' , tip)
|
||||
|
||||
def test_tips_hasattr_failure(self):
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
def __getattribute__(self, attr):
|
||||
raise RuntimeError()
|
||||
|
||||
obj = MyClass()
|
||||
|
||||
_pydev_imports_tipper.generate_imports_tip_for_module(obj)
|
||||
|
||||
def test_inspect(self):
|
||||
|
||||
class C(object):
|
||||
|
||||
def metA(self, a, b):
|
||||
pass
|
||||
|
||||
obj = C.metA
|
||||
if inspect.ismethod (obj):
|
||||
pass
|
||||
# print_ obj.im_func
|
||||
# print_ inspect.getargspec(obj.im_func)
|
||||
Reference in New Issue
Block a user