Skip to content

Commit

Permalink
Merge branch '5.x' into update-pyqt
Browse files Browse the repository at this point in the history
  • Loading branch information
dalthviz authored Mar 10, 2022
2 parents 0ecc773 + 8026178 commit 2ffc68e
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 115 deletions.
6 changes: 3 additions & 3 deletions installers/Windows/req-extras-pull-request.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ matplotlib
cython
sympy

# Spyder external plugins
spyder-terminal>=1.2.1

# Spyder external dependencies (spyder-kernels and qdarkstyle)
./external-deps/spyder-kernels
./external-deps/qdarkstyle

# There are no wheels for version 3.3
cryptography==3.2.1
4 changes: 2 additions & 2 deletions installers/Windows/req-extras-release.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ matplotlib
cython
sympy

# There are no wheels for version 3.3
cryptography==3.2.1
# Spyder external plugins
spyder-terminal>=1.2.1
6 changes: 3 additions & 3 deletions installers/Windows/req-pull-request.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Spyder external plugins
spyder-terminal>=1.2.1

# Spyder external dependencies (spyder-kernels and qdarkstyle)
./external-deps/spyder-kernels
./external-deps/qdarkstyle

# There are no wheels for version 3.3
cryptography==3.2.1
4 changes: 2 additions & 2 deletions installers/Windows/req-release.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# There are no wheels for version 3.3
cryptography==3.2.1
# Spyder external plugins
spyder-terminal>=1.2.1
8 changes: 8 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
# =============================================================================
NAME = 'spyder'
LIBNAME = 'spyder'
WINDOWS_INSTALLER_NAME = os.environ.get('EXE_NAME')

from spyder import __version__, __website_url__ #analysis:ignore


Expand Down Expand Up @@ -243,6 +245,12 @@ def run(self):
'watchdog>=0.10.3'
]

# Replace spyder-kernels constraint to enable
# building Windows installers on PRs
if 'dev' in __version__ and WINDOWS_INSTALLER_NAME:
install_requires.remove('spyder-kernels>=2.2.1,<2.3.0')
install_requires.append('spyder-kernels>=2.2.1,<=2.3.0.dev0')

extras_require = {
'test:platform_system == "Windows"': ['pywin32'],
'test': [
Expand Down
14 changes: 14 additions & 0 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,19 @@ def main_window(request, tmpdir, qtbot):
shell = window.ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
# Wait until console is up
shell = window.ipyconsole.get_current_shellwidget()
try:
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
except Exception:
# Print content of shellwidget and close window
print(shell._control.toPlainText())
client = window.ipyconsole.get_current_client()
if client.info_page != client.blank_page:
print('info_page')
print(client.info_page)
raise

if os.name != 'nt':
# _DummyThread are created if current_thread() is called from them.
Expand Down Expand Up @@ -4607,6 +4620,7 @@ def foo(x):

@pytest.mark.slow
@flaky(max_runs=3)
@pytest.mark.skipif(os.name == 'nt', reason="Tour messes up focus on Windows")
def test_focus_to_consoles(main_window, qtbot):
"""
Check that we give focus to the text widget of our consoles after focus
Expand Down
63 changes: 38 additions & 25 deletions spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,18 @@ def __getattr__(self, attr):
# Wait until the window is fully up
qtbot.waitUntil(lambda: console.get_current_shellwidget() is not None)
shell = console.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
try:
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
except Exception:
# Print content of shellwidget and close window
print(console.get_current_shellwidget(
)._control.toPlainText())
client = console.get_current_client()
if client.info_page != client.blank_page:
print('info_page')
print(client.info_page)
raise

# Check for thread or open file leaks
known_leak = request.node.get_closest_marker('known_leak')
Expand Down Expand Up @@ -1378,30 +1388,33 @@ def test_kernel_crash(ipyconsole, qtbot):
# Create an IPython kernel config file with a bad config
ipy_kernel_cfg = osp.join(get_ipython_dir(), 'profile_default',
'ipython_kernel_config.py')
with open(ipy_kernel_cfg, 'w') as f:
# This option must be a string, not an int
f.write("c.InteractiveShellApp.extra_extension = 1")

ipyconsole.create_new_client()

# Assert that the console is showing an error
qtbot.waitUntil(lambda: ipyconsole.get_clients()[-1].is_error_shown,
timeout=6000)
error_client = ipyconsole.get_clients()[-1]
assert error_client.is_error_shown

# Assert the error contains the text we expect
webview = error_client.infowidget
if WEBENGINE:
webpage = webview.page()
else:
webpage = webview.page().mainFrame()
qtbot.waitUntil(
lambda: check_text(webpage, "Bad config encountered"),
timeout=6000)
try:
with open(ipy_kernel_cfg, 'w') as f:
# This option must be a string, not an int
f.write("c.InteractiveShellApp.extra_extension = 1")

ipyconsole.get_widget().close_cached_kernel()
ipyconsole.create_new_client()

# Assert that the console is showing an error
qtbot.waitUntil(lambda: ipyconsole.get_clients()[-1].is_error_shown,
timeout=6000)
error_client = ipyconsole.get_clients()[-1]
assert error_client.is_error_shown

# Assert the error contains the text we expect
webview = error_client.infowidget
if WEBENGINE:
webpage = webview.page()
else:
webpage = webview.page().mainFrame()

# Remove bad kernel config file
os.remove(ipy_kernel_cfg)
qtbot.waitUntil(
lambda: check_text(webpage, "Bad config encountered"),
timeout=6000)
finally:
# Remove bad kernel config file
os.remove(ipy_kernel_cfg)


@flaky(max_runs=3)
Expand Down
27 changes: 25 additions & 2 deletions spyder/plugins/ipythonconsole/utils/stdfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,34 @@
# Standard library imports.
import codecs
import os
import os.path as osp

# Local imports
from spyder.py3compat import to_text_string
from spyder.utils.encoding import get_coding
from spyder.utils.programs import get_temp_dir


def std_filename(connection_file, extension, std_dir=None):
"""Filename to save kernel output."""
json_file = osp.basename(connection_file)
file = json_file.split('.json')[0] + extension
if std_dir is not None:
file = osp.join(std_dir, file)
else:
try:
file = osp.join(get_temp_dir(), file)
except (IOError, OSError):
file = None
return file


class StdFile:
def __init__(self, filename):
self.filename = filename
def __init__(self, connection_file, extension=None, std_dir=None):
if extension is None:
self.filename = connection_file
else:
self.filename = std_filename(connection_file, extension, std_dir)
self._mtime = 0
self._cursor = 0
self._handle = None
Expand Down Expand Up @@ -92,3 +111,7 @@ def poll_file_change(self):
ret_text = text[self._cursor:]
self._cursor = len(text)
return ret_text

def copy(self):
"""Return a copy."""
return StdFile(self.filename)
85 changes: 33 additions & 52 deletions spyder/plugins/ipythonconsole/widgets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@
from spyder.utils.encoding import get_coding
from spyder.utils.environ import RemoteEnvDialog
from spyder.utils.palette import QStylePalette
from spyder.utils.programs import get_temp_dir
from spyder.utils.qthelpers import add_actions, DialogManager
from spyder.py3compat import to_text_string
from spyder.plugins.ipythonconsole.utils.stdfile import StdFile
from spyder.plugins.ipythonconsole.widgets import ShellWidget
from spyder.widgets.collectionseditor import CollectionsEditor
from spyder.widgets.mixins import SaveHistoryMixin
Expand Down Expand Up @@ -109,7 +107,9 @@ def __init__(self, parent, id_,
css_path=None,
configuration=None,
handlers={},
std_dir=None):
stderr_obj=None,
stdout_obj=None,
fault_obj=None):
super(ClientWidget, self).__init__(parent)
SaveHistoryMixin.__init__(self, history_filename)

Expand All @@ -132,7 +132,6 @@ def __init__(self, parent, id_,
self.options_button = options_button
self.history = []
self.allow_rename = True
self.std_dir = std_dir
self.is_error_shown = False
self.error_text = None
self.restart_thread = None
Expand Down Expand Up @@ -180,22 +179,16 @@ def __init__(self, parent, id_,
self.dialog_manager = DialogManager()

# --- Standard files handling
self.stderr_obj = None
self.stdout_obj = None
self.fault_obj = None
self.stderr_obj = stderr_obj
self.stdout_obj = stdout_obj
self.fault_obj = fault_obj
self.std_poll_timer = None
if not self.is_external_kernel:
# Cannot create std files for external kernels
self.stderr_obj = StdFile(self.std_filename('.stderr'))
self.stdout_obj = StdFile(self.std_filename('.stdout'))
if self.stderr_obj is not None or self.stdout_obj is not None:
self.std_poll_timer = QTimer(self)
self.std_poll_timer.timeout.connect(self.poll_std_file_change)
self.std_poll_timer.setInterval(1000)
self.std_poll_timer.start()
self.shellwidget.executed.connect(self.poll_std_file_change)
if self.hostname is None:
# Cannot read file that is not on this computer
self.fault_obj = StdFile(self.std_filename('.fault'))

self.start_successful = False

Expand Down Expand Up @@ -356,20 +349,6 @@ def _connect_control_signals(self):
self.container.find_widget.show)

# ----- Public API --------------------------------------------------------
def std_filename(self, extension):
"""Filename to save kernel output."""
file = None
if self.connection_file is not None:
file = self.kernel_id + extension
if self.std_dir is not None:
file = osp.join(self.std_dir, file)
else:
try:
file = osp.join(get_temp_dir(), file)
except (IOError, OSError):
file = None
return file

@property
def kernel_id(self):
"""Get kernel id."""
Expand Down Expand Up @@ -397,31 +376,33 @@ def remove_std_files(self, is_last_client=True):
def poll_std_file_change(self):
"""Check if the stderr or stdout file just changed."""
self.shellwidget.call_kernel().flush_std()
stderr = self.stderr_obj.poll_file_change()
starting = self.shellwidget._starting
if stderr:
if self.is_benign_error(stderr):
return
if self.shellwidget.isHidden():
# Avoid printing the same thing again
if self.error_text != '<tt>%s</tt>' % stderr:
full_stderr = self.stderr_obj.get_contents()
self.show_kernel_error('<tt>%s</tt>' % full_stderr)
if starting:
self.shellwidget.banner = (
stderr + '\n' + self.shellwidget.banner)
else:
self.shellwidget._append_plain_text(
'\n' + stderr, before_prompt=True)

stdout = self.stdout_obj.poll_file_change()
if stdout:
if starting:
self.shellwidget.banner = (
stdout + '\n' + self.shellwidget.banner)
else:
self.shellwidget._append_plain_text(
'\n' + stdout, before_prompt=True)
if self.stderr_obj is not None:
stderr = self.stderr_obj.poll_file_change()
if stderr:
if self.is_benign_error(stderr):
return
if self.shellwidget.isHidden():
# Avoid printing the same thing again
if self.error_text != '<tt>%s</tt>' % stderr:
full_stderr = self.stderr_obj.get_contents()
self.show_kernel_error('<tt>%s</tt>' % full_stderr)
if starting:
self.shellwidget.banner = (
stderr + '\n' + self.shellwidget.banner)
else:
self.shellwidget._append_plain_text(
'\n' + stderr, before_prompt=True)

if self.stdout_obj is not None:
stdout = self.stdout_obj.poll_file_change()
if stdout:
if starting:
self.shellwidget.banner = (
stdout + '\n' + self.shellwidget.banner)
else:
self.shellwidget._append_plain_text(
'\n' + stdout, before_prompt=True)

def configure_shellwidget(self, give_focus=True):
"""Configure shellwidget after kernel is connected."""
Expand Down
Loading

0 comments on commit 2ffc68e

Please sign in to comment.