Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-spyder-kernels for openSUSE:Factory checked in at 2022-11-07 13:52:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-spyder-kernels (Old) and /work/SRC/openSUSE:Factory/.python-spyder-kernels.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-spyder-kernels" Mon Nov 7 13:52:08 2022 rev:37 rq:1034141 version:2.4.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-spyder-kernels/python-spyder-kernels.changes 2022-09-04 22:12:04.392334803 +0200 +++ /work/SRC/openSUSE:Factory/.python-spyder-kernels.new.1597/python-spyder-kernels.changes 2022-11-07 13:52:14.691988207 +0100 @@ -1,0 +2,7 @@ +Sun Nov 6 15:08:20 UTC 2022 - Ben Greiner <c...@bnavigator.de> + +- Update to verison 2.4.0 + * Add support for Python 3.11 + * Flush standard streams after execution. + +------------------------------------------------------------------- Old: ---- python-spyder-kernels-2.3.3.tar.gz New: ---- python-spyder-kernels-2.4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-spyder-kernels.spec ++++++ --- /var/tmp/diff_new_pack.POUVzs/_old 2022-11-07 13:52:15.195991041 +0100 +++ /var/tmp/diff_new_pack.POUVzs/_new 2022-11-07 13:52:15.199991063 +0100 @@ -16,12 +16,10 @@ # -%{?!python_module:%define python_module() python3-%{**}} -%define skip_python2 1 # flaky for obs, only test locally %bcond_with dasktest Name: python-spyder-kernels -Version: 2.3.3 +Version: 2.4.0 Release: 0 Summary: Jupyter kernels for Spyder's console License: MIT @@ -29,15 +27,17 @@ URL: https://github.com/spyder-ide/spyder-kernels # PyPI tarballs do not include the tests: https://github.com/spyder-ide/spyder-kernels/issues/66 Source: %{url}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz +BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros # SECTION test requirements BuildRequires: %{python_module Cython} +BuildRequires: %{python_module Django} BuildRequires: %{python_module Pillow} BuildRequires: %{python_module cloudpickle} BuildRequires: %{python_module flaky} -BuildRequires: %{python_module ipykernel >= 6.9.2 with %python-ipykernel < 7} +BuildRequires: %{python_module ipykernel >= 6.16.1 with %python-ipykernel < 7} BuildRequires: %{python_module ipython >= 7.31.1} BuildRequires: %{python_module jupyter_client >= 7.3.4 with %python-jupyter_client < 8} BuildRequires: %{python_module matplotlib} @@ -56,7 +56,7 @@ Requires: python-ipython >= 7.31.1 Requires: python-pyzmq >= 22.1 Requires: python-wurlitzer >= 1.0.3 -Requires: (python-ipykernel >= 6.9.2 with python-ipykernel < 7) +Requires: (python-ipykernel >= 6.16.1 with python-ipykernel < 7) Requires: (python-jupyter_client >= 7.3.4 with python-jupyter_client < 8) BuildArch: noarch ++++++ python-spyder-kernels-2.3.3.tar.gz -> python-spyder-kernels-2.4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/CHANGELOG.md new/spyder-kernels-2.4.0/CHANGELOG.md --- old/spyder-kernels-2.3.3/CHANGELOG.md 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/CHANGELOG.md 2022-11-03 01:06:16.000000000 +0100 @@ -1,5 +1,29 @@ # History of changes +## Version 2.4.0 (2022-11-02) + +### New features + +* Add support for Python 3.11 +* Flush standard streams after execution. + +### Pull Requests Merged + +* [PR 428](https://github.com/spyder-ide/spyder-kernels/pull/428) - PR: Patch for CVE-2007-4559 Tar directory traversal, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 426](https://github.com/spyder-ide/spyder-kernels/pull/426) - PR: Update ipykernel constraint to >=6.16.1, by [@dalthviz](https://github.com/dalthviz) +* [PR 423](https://github.com/spyder-ide/spyder-kernels/pull/423) - PR: Fix lineno range, by [@impact27](https://github.com/impact27) ([19862](https://github.com/spyder-ide/spyder/issues/19862)) +* [PR 422](https://github.com/spyder-ide/spyder-kernels/pull/422) - PR: Make comm lock reentrant, by [@impact27](https://github.com/impact27) +* [PR 420](https://github.com/spyder-ide/spyder-kernels/pull/420) - PR: Only access sys.stdout and sys.stderr once, by [@impact27](https://github.com/impact27) +* [PR 416](https://github.com/spyder-ide/spyder-kernels/pull/416) - PR: Fix some errors when computing the namespace view, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 415](https://github.com/spyder-ide/spyder-kernels/pull/415) - PR: Fix tk eventloop handling when debugging on Windows, by [@dalthviz](https://github.com/dalthviz) +* [PR 413](https://github.com/spyder-ide/spyder-kernels/pull/413) - PR: Flush standard streams after execution, by [@impact27](https://github.com/impact27) + +In this release 8 pull requests were closed. + + +---- + + ## Version 2.3.3 (2022-08-28) ### Issues Closed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/requirements/posix.txt new/spyder-kernels-2.4.0/requirements/posix.txt --- old/spyder-kernels-2.3.3/requirements/posix.txt 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/requirements/posix.txt 2022-11-03 01:06:16.000000000 +0100 @@ -1,5 +1,5 @@ cloudpickle -ipykernel>=6.9.2,<7 +ipykernel>=6.16.1,<7 ipython>=7.31.1,<8 jupyter_client>=7.3.4,<8 pyzmq>=22.1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/requirements/tests.txt new/spyder-kernels-2.4.0/requirements/tests.txt --- old/spyder-kernels-2.3.3/requirements/tests.txt 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/requirements/tests.txt 2022-11-03 01:06:16.000000000 +0100 @@ -11,3 +11,4 @@ scipy xarray pillow +django diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/requirements/windows.txt new/spyder-kernels-2.4.0/requirements/windows.txt --- old/spyder-kernels-2.3.3/requirements/windows.txt 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/requirements/windows.txt 2022-11-03 01:06:16.000000000 +0100 @@ -1,5 +1,5 @@ cloudpickle -ipykernel>=6.9.2,<7 +ipykernel>=6.16.1,<7 ipython>=7.31.1,<8 jupyter_client>=7.3.4,<8 pyzmq>=22.1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/setup.py new/spyder-kernels-2.4.0/setup.py --- old/spyder-kernels-2.3.3/setup.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/setup.py 2022-11-03 01:06:16.000000000 +0100 @@ -40,7 +40,7 @@ 'backports.functools-lru-cache; python_version<"3"', 'cloudpickle', 'ipykernel<5; python_version<"3"', - 'ipykernel>=6.9.2,<7; python_version>="3"', + 'ipykernel>=6.16.1,<7; python_version>="3"', 'ipython<6; python_version<"3"', 'ipython>=7.31.1,<8; python_version>="3"', 'jupyter-client>=5.3.4,<6; python_version<"3"', @@ -64,6 +64,7 @@ 'scipy', 'xarray', 'pillow', + 'django', ] setup( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/_version.py new/spyder-kernels-2.4.0/spyder_kernels/_version.py --- old/spyder-kernels-2.3.3/spyder_kernels/_version.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/_version.py 2022-11-03 01:06:16.000000000 +0100 @@ -8,5 +8,5 @@ """Version File.""" -VERSION_INFO = (2, 3, 3) +VERSION_INFO = (2, 4, 0) __version__ = '.'.join(map(str, VERSION_INFO)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/comms/frontendcomm.py new/spyder-kernels-2.4.0/spyder_kernels/comms/frontendcomm.py --- old/spyder-kernels-2.3.3/spyder_kernels/comms/frontendcomm.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/comms/frontendcomm.py 2022-11-03 01:06:16.000000000 +0100 @@ -64,7 +64,7 @@ self.register_call_handler('_send_comm_config', self._send_comm_config) - self.comm_lock = threading.Lock() + self.comm_lock = threading.RLock() # self.kernel.parent is IPKernelApp unless we are in tests if self.kernel.parent: @@ -259,19 +259,22 @@ def _remote_callback(self, call_name, call_args, call_kwargs): """Call the callback function for the remote call.""" - saved_stdout_write = sys.stdout.write - saved_stderr_write = sys.stderr.write - thread_id = threading.get_ident() - sys.stdout.write = WriteWrapper( - saved_stdout_write, call_name, thread_id) - sys.stderr.write = WriteWrapper( - saved_stderr_write, call_name, thread_id) - try: - return super(FrontendComm, self)._remote_callback( - call_name, call_args, call_kwargs) - finally: - sys.stdout.write = saved_stdout_write - sys.stderr.write = saved_stderr_write + with self.comm_lock: + current_stdout = sys.stdout + current_stderr = sys.stderr + saved_stdout_write = current_stdout.write + saved_stderr_write = current_stderr.write + thread_id = threading.get_ident() + current_stdout.write = WriteWrapper( + saved_stdout_write, call_name, thread_id) + current_stderr.write = WriteWrapper( + saved_stderr_write, call_name, thread_id) + try: + return super(FrontendComm, self)._remote_callback( + call_name, call_args, call_kwargs) + finally: + current_stdout.write = saved_stdout_write + current_stderr.write = saved_stderr_write class WriteWrapper(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/console/kernel.py new/spyder-kernels-2.4.0/spyder_kernels/console/kernel.py --- old/spyder-kernels-2.3.3/spyder_kernels/console/kernel.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/console/kernel.py 2022-11-03 01:06:16.000000000 +0100 @@ -20,6 +20,7 @@ # Third-party imports import ipykernel from ipykernel.ipkernel import IPythonKernel +from ipykernel import eventloops from traitlets.config.loader import LazyConfigValue # Local imports @@ -88,7 +89,6 @@ 'pdb_input_reply': self.pdb_input_reply, '_interrupt_eventloop': self._interrupt_eventloop, 'enable_faulthandler': self.enable_faulthandler, - "flush_std": self.flush_std, } for call_id in handlers: self.frontend_comm.register_call_handler( @@ -120,11 +120,6 @@ callback=callback, timeout=timeout) - def flush_std(self): - """Flush C standard streams.""" - sys.__stderr__.flush() - sys.__stdout__.flush() - def enable_faulthandler(self, fn): """ Open a file to save the faulthandling and identifiers for @@ -210,9 +205,9 @@ properties = {} for name, value in list(data.items()): properties[name] = { - 'is_list': isinstance(value, (tuple, list)), - 'is_dict': isinstance(value, dict), - 'is_set': isinstance(value, set), + 'is_list': self._is_list(value), + 'is_dict': self._is_dict(value), + 'is_set': self._is_set(value), 'len': self._get_len(value), 'is_array': self._is_array(value), 'is_image': self._is_image(value), @@ -404,48 +399,43 @@ """ # Mapping from frameworks to backend names. mapping = { - 'qt': 'QtAgg', # For Matplotlib 3.5+ - 'qt5': 'Qt5Agg', + 'qt': 'QtAgg', 'tk': 'TkAgg', 'macosx': 'MacOSX' } - try: - # --- Get interactive framework - framework = None + # --- Get interactive framework + framework = None - # This is necessary because _get_running_interactive_framework - # can't detect Tk in a Jupyter kernel. - if hasattr(self, 'app_wrapper'): - if hasattr(self.app_wrapper, 'app'): - import tkinter - if isinstance(self.app_wrapper.app, tkinter.Tk): - framework = 'tk' - - if framework is None: - try: - # This is necessary for Matplotlib 3.3.0+ - from matplotlib import cbook - framework = cbook._get_running_interactive_framework() - except AttributeError: - # For older versions - from matplotlib import backends - framework = backends._get_running_interactive_framework() - - # --- Return backend according to framework - if framework is None: - # Since no interactive backend has been set yet, this is - # equivalent to having the inline one. - return 0 - elif framework in mapping: - return MPL_BACKENDS_TO_SPYDER[mapping[framework]] + # Detect if there is a graphical framework running by checking the + # eventloop function attached to the kernel.eventloop attribute (see + # `ipykernel.eventloops.enable_gui` for context). + from IPython.core.getipython import get_ipython + loop_func = get_ipython().kernel.eventloop + + if loop_func is not None: + if loop_func == eventloops.loop_tk: + framework = 'tk' + elif loop_func == eventloops.loop_qt5: + framework = 'qt' + elif loop_func == eventloops.loop_cocoa: + framework = 'macosx' else: - # This covers the case of other backends (e.g. Wx or Gtk) - # which users can set interactively with the %matplotlib - # magic but not through our Preferences. - return -1 - except Exception: - return None + # Spyder doesn't handle other backends + framework = 'other' + + # --- Return backend according to framework + if framework is None: + # Since no interactive backend has been set yet, this is + # equivalent to having the inline one. + return 0 + elif framework in mapping: + return MPL_BACKENDS_TO_SPYDER[mapping[framework]] + else: + # This covers the case of other backends (e.g. Wx or Gtk) + # which users can set interactively with the %matplotlib + # magic but not through our Preferences. + return -1 def set_matplotlib_backend(self, backend, pylab=False): """Set matplotlib backend given a Spyder backend option.""" @@ -668,6 +658,30 @@ except: return False + def _is_list(self, var): + """Return True if variable is a list or tuple.""" + # The try/except is necessary to fix spyder-ide/spyder#19516. + try: + return isinstance(var, (tuple, list)) + except Exception: + return False + + def _is_dict(self, var): + """Return True if variable is a dictionary.""" + # The try/except is necessary to fix spyder-ide/spyder#19516. + try: + return isinstance(var, dict) + except Exception: + return False + + def _is_set(self, var): + """Return True if variable is a set.""" + # The try/except is necessary to fix spyder-ide/spyder#19516. + try: + return isinstance(var, set) + except Exception: + return False + def _get_array_shape(self, var): """Return array's shape""" try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/console/shell.py new/spyder-kernels-2.4.0/spyder_kernels/console/shell.py --- old/spyder-kernels-2.3.3/spyder_kernels/console/shell.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/console/shell.py 2022-11-03 01:06:16.000000000 +0100 @@ -26,6 +26,9 @@ self._pdb_obj = None super(SpyderShell, self).__init__(*args, **kwargs) + # register post_execute + self.events.register('post_execute', self.do_post_execute) + # ---- Methods overriden by us. def ask_exit(self): """Engage the exit actions.""" @@ -104,3 +107,9 @@ def user_ns(self, namespace): """Set user_ns.""" self.__user_ns = namespace + + def do_post_execute(self): + """Flush __std*__ after execution.""" + # Flush C standard streams. + sys.__stderr__.flush() + sys.__stdout__.flush() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/console/tests/test_console_kernel.py new/spyder-kernels-2.4.0/spyder_kernels/console/tests/test_console_kernel.py --- old/spyder-kernels-2.3.3/spyder_kernels/console/tests/test_console_kernel.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/console/tests/test_console_kernel.py 2022-11-03 01:06:16.000000000 +0100 @@ -1181,5 +1181,37 @@ break +def test_non_strings_in_locals(kernel): + """ + Test that we can hande non-string entries in `locals` when bulding the + namespace view. + + This is a regression test for issue spyder-ide/spyder#19145 + """ + if IPYKERNEL_6: + execute = asyncio.run(kernel.do_execute( + 'locals().update({1:2})', True)) + else: + execute = kernel.do_execute('locals().update({1:2})', True) + + nsview = repr(kernel.get_namespace_view()) + assert "1:" in nsview + + +@pytest.mark.skipif( + sys.version_info[0] < 3, reason="Doesn't work with Python 2") +def test_django_settings(kernel): + """ + Test that we don't generate errors when importing `django.conf.settings`. + + This is a regression test for issue spyder-ide/spyder#19516 + """ + execute = asyncio.run(kernel.do_execute( + 'from django.conf import settings', True)) + + nsview = repr(kernel.get_namespace_view()) + assert "'settings':" in nsview + + if __name__ == "__main__": pytest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/customize/spyderpdb.py new/spyder-kernels-2.4.0/spyder_kernels/customize/spyderpdb.py --- old/spyder-kernels-2.3.3/spyder_kernels/customize/spyderpdb.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/customize/spyderpdb.py 2022-11-03 01:06:16.000000000 +0100 @@ -10,6 +10,7 @@ import ast import bdb import logging +import os import sys import traceback import threading @@ -684,6 +685,8 @@ # Flush output before making the request. sys.stderr.flush() sys.stdout.flush() + sys.__stderr__.flush() + sys.__stdout__.flush() # Send the input request. self._cmd_input_line = None @@ -701,7 +704,13 @@ if is_main_thread and kernel.eventloop: while self._cmd_input_line is None: eventloop = kernel.eventloop - if eventloop: + # Check if the current backend is Tk on Windows + # to let GUI update. + # See spyder-ide/spyder#17523 + if (eventloop and hasattr(kernel, "app_wrapper") and + os.name == "nt"): + kernel.app_wrapper.app.update() + elif eventloop: eventloop(kernel) else: break @@ -731,11 +740,10 @@ return line def postcmd(self, stop, line): - """ - Notify spyder about (possibly) changed frame - - Note: The PDB commands ???up???, ???down??? and ???jump??? change the current frame. - """ + """Hook method executed just after a command dispatch is finished.""" + # Flush in case the command produced output on underlying outputs + sys.__stderr__.flush() + sys.__stdout__.flush() self.publish_pdb_state() return super(SpyderPdb, self).postcmd(stop, line) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/customize/utils.py new/spyder-kernels-2.4.0/spyder_kernels/customize/utils.py --- old/spyder-kernels-2.3.3/spyder_kernels/customize/utils.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/customize/utils.py 2022-11-03 01:06:16.000000000 +0100 @@ -8,6 +8,7 @@ import ast import os import re +import sys import sysconfig @@ -113,6 +114,14 @@ # Fix line number and column offset assign_node.lineno = expr_node.lineno assign_node.col_offset = expr_node.col_offset + if sys.version_info[:2] >= (3, 8): + # Exists from 3.8, necessary from 3.11 + assign_node.end_lineno = expr_node.end_lineno + if assign_node.lineno == assign_node.end_lineno: + # Add 'globals()[{}] = ' and remove 'None' + assign_node.end_col_offset += expr_node.end_col_offset - 4 + else: + assign_node.end_col_offset = expr_node.end_col_offset code_ast.body[-1] = assign_node return code_ast, capture_last_expression diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/utils/iofuncs.py new/spyder-kernels-2.4.0/spyder_kernels/utils/iofuncs.py --- old/spyder-kernels-2.3.3/spyder_kernels/utils/iofuncs.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/utils/iofuncs.py 2022-11-03 01:06:16.000000000 +0100 @@ -23,7 +23,6 @@ import tempfile import shutil import types -import warnings import json import inspect import dis @@ -370,6 +369,27 @@ return error_message +def is_within_directory(directory, target): + """Check if a file is within a directory.""" + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + prefix = os.path.commonprefix([abs_directory, abs_target]) + return prefix == abs_directory + + +def safe_extract(tar, path=".", members=None, numeric_owner=False): + """Safely extract a tar file.""" + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception( + "Attempted path traversal in tar file {}".format( + repr(tar.name) + ) + ) + tar.extractall(path, members, numeric_owner=numeric_owner) + + def load_dictionary(filename): """Load dictionary from .spydata file""" filename = osp.abspath(filename) @@ -380,7 +400,11 @@ error_message = None try: with tarfile.open(filename, "r") as tar: - tar.extractall() + if PY2: + tar.extractall() + else: + safe_extract(tar) + pickle_filename = glob.glob('*.pickle')[0] # 'New' format (Spyder >=2.2 for Python 2 and Python 3) with open(pickle_filename, 'rb') as fdesc: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.3.3/spyder_kernels/utils/nsview.py new/spyder-kernels-2.4.0/spyder_kernels/utils/nsview.py --- old/spyder-kernels-2.3.3/spyder_kernels/utils/nsview.py 2022-08-28 03:53:56.000000000 +0200 +++ new/spyder-kernels-2.4.0/spyder_kernels/utils/nsview.py 2022-11-03 01:06:16.000000000 +0100 @@ -36,16 +36,27 @@ def get_numpy_dtype(obj): - """Return NumPy data type associated to obj - Return None if NumPy is not available - or if obj is not a NumPy array or scalar""" + """ + Return Numpy data type associated to `obj`. + + Return None if Numpy is not available, if we get errors or if `obj` is not + a Numpy array or scalar. + """ + # Check if NumPy is available if np.ndarray is not FakeObject: - # NumPy is available - if isinstance(obj, np.generic) or isinstance(obj, np.ndarray): - # Numpy scalars all inherit from np.generic. - # Numpy arrays all inherit from np.ndarray. - # If we check that we are certain we have one of these - # types then we are less likely to generate an exception below. + # All Numpy scalars inherit from np.generic and all Numpy arrays + # inherit from np.ndarray. If we check that we are certain we have one + # of these types then we are less likely to generate an exception + # below. + # Note: The try/except is necessary to fix spyder-ide/spyder#19516. + try: + scalar_or_array = ( + isinstance(obj, np.generic) or isinstance(obj, np.ndarray) + ) + except Exception: + return + + if scalar_or_array: try: return obj.dtype.type except (AttributeError, RuntimeError): @@ -499,21 +510,25 @@ # ============================================================================= def get_type_string(item): """Return type string of an object.""" - # Numpy objects (don't change the order!) - if isinstance(item, np.ma.MaskedArray): - return "MaskedArray" - if isinstance(item, np.matrix): - return "Matrix" - if isinstance(item, np.ndarray): - return "NDArray" - - # Pandas objects - if isinstance(item, pd.DataFrame): - return "DataFrame" - if isinstance(item, pd.Index): - return type(item).__name__ - if isinstance(item, pd.Series): - return "Series" + # The try/except is necessary to fix spyder-ide/spyder#19516. + try: + # Numpy objects (don't change the order!) + if isinstance(item, np.ma.MaskedArray): + return "MaskedArray" + if isinstance(item, np.matrix): + return "Matrix" + if isinstance(item, np.ndarray): + return "NDArray" + + # Pandas objects + if isinstance(item, pd.DataFrame): + return "DataFrame" + if isinstance(item, pd.Index): + return type(item).__name__ + if isinstance(item, pd.Series): + return "Series" + except Exception: + pass found = re.findall(r"<(?:type|class) '(\S*)'>", to_text_string(type(item))) @@ -534,13 +549,17 @@ def get_human_readable_type(item): """Return human-readable type string of an item""" - if isinstance(item, (np.ndarray, np.ma.MaskedArray)): - return u'Array of ' + item.dtype.name - elif isinstance(item, PIL.Image.Image): - return "Image" - else: - text = get_type_string(item) - return text[text.find('.')+1:] + # The try/except is necessary to fix spyder-ide/spyder#19516. + try: + if isinstance(item, (np.ndarray, np.ma.MaskedArray)): + return u'Array of ' + item.dtype.name + elif isinstance(item, PIL.Image.Image): + return "Image" + else: + text = get_type_string(item) + return text[text.find('.')+1:] + except Exception: + return 'Unknown' #============================================================================== @@ -593,11 +612,13 @@ excluded_names=None, exclude_callables_and_modules=None): """Keep objects in namespace view according to different criteria.""" output_dict = {} + _is_string = is_type_text_string + for key, value in list(input_dict.items()): excluded = ( - (exclude_private and key.startswith('_')) or - (exclude_capitalized and key[0].isupper()) or - (exclude_uppercase and key.isupper() and + (exclude_private and _is_string(key) and key.startswith('_')) or + (exclude_capitalized and _is_string(key) and key[0].isupper()) or + (exclude_uppercase and _is_string(key) and key.isupper() and len(key) > 1 and not key[1:].isdigit()) or (key in excluded_names) or (exclude_callables_and_modules and is_callable_or_module(value)) or