Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Improve startup time in several ways #15857

Merged
merged 17 commits into from
Jul 4, 2021
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
93a5af0
git subrepo clone --branch=delayed-modules --force https://github.com…
ccordoba12 Jun 13, 2021
af5b6db
Variable Explorer: Use new lazy modules from spyder-kernels
ccordoba12 Jun 13, 2021
dcba93d
git subrepo pull --remote=https://github.com/ccordoba12/spyder-kernel…
ccordoba12 Jun 13, 2021
ac60957
Contributing: Fix commands to pull branch from subrepos
ccordoba12 Jun 13, 2021
5dd062b
Avoid importing Matplotlib and Numpy at startup
ccordoba12 Jun 13, 2021
e254e44
Application: Compute dependencies in a thread to not block the interface
ccordoba12 Jun 13, 2021
2b47c42
Remove old CONF_FROM_OPTIONS class constant
ccordoba12 Jun 13, 2021
605fc65
Application: Make missing dependencies dialog non-modal
ccordoba12 Jun 13, 2021
6aef21c
Main window: Improve startup time by calling processEvents before and…
ccordoba12 Jun 13, 2021
3851d58
Stylesheet: Don't compute stylesheets when importing the module
ccordoba12 Jun 13, 2021
9fc74bc
Testing: Fix collectioneditor tests
ccordoba12 Jun 14, 2021
201e97e
Variable Explorer: Use numpy lazy module to safely import ArrayEditor
ccordoba12 Jun 14, 2021
c513132
Variable Explorer: Use pandas lazy module to safely import DataFrameE…
ccordoba12 Jun 14, 2021
7b99f08
Merge branch '5.x' into lazy-modules
ccordoba12 Jul 4, 2021
b22c4c2
Contributing: Mention again to use subrepo clone instead of pull beca…
ccordoba12 Jul 4, 2021
09fd9d2
git subrepo clone (merge) --branch=delayed-modules --force https://gi…
ccordoba12 Jul 4, 2021
fb3bc3b
git subrepo clone (merge) --branch=2.x --force https://github.com/spy…
ccordoba12 Jul 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ As an example, let's assume that (i) your Github user name is `myuser`; (ii) you
```
$ cd ~/spyder
$ git checkout fix_in_spyder
$ git subrepo clone https://github.com/myuser/spyder-kernels.git external-deps/spyder-kernels -b fix_in_kernel -f
$ git subrepo pull external-deps/spyder-kernels --remote https://github.com/myuser/spyder-kernels.git --branch fix_in_kernel
```

* You can now open a PR on `https://github.com/spyder-ide/spyder` and on `https://github.com/spyder-ide/spyder-kernels` for each of your branches.
Expand Down Expand Up @@ -218,7 +218,7 @@ Due to that, a clone of that project is placed in the `external-deps` directory,

```
$ git checkout -b fix_in_spyder
$ git subrepo clone https://github.com/myuser/python-language-server.git external-deps/python-language-server -b fix_in_pyls -f
$ git subrepo pull external-deps/python-language-server --remote https://github.com/myuser/python-language-server.git --branch fix_in_pyls
```

and then commit the changes you need to make in Spyder.
Expand Down
8 changes: 4 additions & 4 deletions external-deps/spyder-kernels/.gitrepo
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
;
[subrepo]
remote = https://github.com/spyder-ide/spyder-kernels.git
branch = 2.x
commit = d1db5085de80587d04274fd72b3915820df8a2e6
parent = 3c57ee74c73884ea3c0a24d0ec40796453657823
remote = https://github.com/ccordoba12/spyder-kernels.git
branch = delayed-modules
commit = 6c7a9d8ebf0331c01d40b93c71edba92dca3c007
parent = af5b6db77334d2b7d36dde5f35e582dfa7f9d38c
method = merge
cmdver = 0.4.3
12 changes: 3 additions & 9 deletions external-deps/spyder-kernels/spyder_kernels/console/kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
from spyder_kernels.py3compat import TEXT_TYPES, to_text_string
from spyder_kernels.comms.frontendcomm import FrontendComm
from spyder_kernels.py3compat import PY3, input
from spyder_kernels.utils.misc import (
from spyder_kernels.utils.iofuncs import iofunctions
from spyder_kernels.utils.mpl import (
MPL_BACKENDS_FROM_SPYDER, MPL_BACKENDS_TO_SPYDER, INLINE_FIGURE_FORMATS)
from spyder_kernels.utils.nsview import get_remote_data, make_remote_view


# Excluded variables from the Variable Explorer (i.e. they are not
Expand Down Expand Up @@ -157,7 +159,6 @@ def get_namespace_view(self):
* 'numpy_type' is its Numpy type (if any) computed with
`get_numpy_type_string`.
"""
from spyder_kernels.utils.nsview import make_remote_view

settings = self.namespace_view_settings
if settings:
Expand All @@ -172,8 +173,6 @@ def get_var_properties(self):
Get some properties of the variables in the current
namespace
"""
from spyder_kernels.utils.nsview import get_remote_data

settings = self.namespace_view_settings
if settings:
ns = self._get_current_namespace()
Expand Down Expand Up @@ -234,11 +233,9 @@ def load_data(self, filename, ext, overwrite=False):
In the other hand, with 'overwrite=False', a new variable will be
created with a sufix starting with 000 i.e 'var000' (default behavior).
"""
from spyder_kernels.utils.iofuncs import iofunctions
from spyder_kernels.utils.misc import fix_reference_name

glbs = self._mglobals()

load_func = iofunctions.load_funcs[ext]
data, error_message = load_func(filename)

Expand All @@ -261,9 +258,6 @@ def load_data(self, filename, ext, overwrite=False):

def save_namespace(self, filename):
"""Save namespace into filename"""
from spyder_kernels.utils.nsview import get_remote_data
from spyder_kernels.utils.iofuncs import iofunctions

ns = self._get_current_namespace()
settings = self.namespace_view_settings
data = get_remote_data(ns, settings, mode='picklable',
Expand Down
5 changes: 3 additions & 2 deletions external-deps/spyder-kernels/spyder_kernels/console/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
import site

# Local imports
from spyder_kernels.utils.misc import (
MPL_BACKENDS_FROM_SPYDER, INLINE_FIGURE_FORMATS, is_module_installed)
from spyder_kernels.utils.misc import is_module_installed
from spyder_kernels.utils.mpl import (
MPL_BACKENDS_FROM_SPYDER, INLINE_FIGURE_FORMATS)


PY2 = sys.version[0] == '2'
Expand Down
211 changes: 95 additions & 116 deletions external-deps/spyder-kernels/spyder_kernels/utils/iofuncs.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,10 @@
import copy
import glob

# Third party imports
# - If pandas fails to import here (for any reason), Spyder
# will crash at startup (e.g. see Issue 2300)
# - This also prevents Spyder to start IPython kernels
# (see Issue 2456)
try:
import pandas as pd
except:
pd = None #analysis:ignore

# Local imports
from spyder_kernels.py3compat import getcwd, pickle, PY2, to_text_string
from spyder_kernels.utils.lazymodules import (
FakeObject, numpy as np, pandas as pd, PIL, scipy as sp)


class MatlabStruct(dict):
Expand Down Expand Up @@ -110,8 +102,6 @@ def get_matlab_value(val):
From the oct2py project, see
https://pythonhosted.org/oct2py/conversions.html
"""
import numpy as np

# Extract each item of a list.
if isinstance(val, list):
return [get_matlab_value(v) for v in val]
Expand Down Expand Up @@ -156,113 +146,102 @@ def get_matlab_value(val):
return val


try:
import numpy as np
def load_matlab(filename):
if sp.io is FakeObject:
return None, ''

try:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
import scipy.io as spio
except AttributeError:
# Python 2.5: warnings.catch_warnings was introduced in Python 2.6
import scipy.io as spio # analysis:ignore
except:
spio = None

if spio is None:
load_matlab = None
save_matlab = None
else:
def load_matlab(filename):
try:
out = spio.loadmat(filename, struct_as_record=True)
data = dict()
for (key, value) in out.items():
data[key] = get_matlab_value(value)
return data, None
except Exception as error:
return None, str(error)

def save_matlab(data, filename):
try:
spio.savemat(filename, data, oned_as='row')
except Exception as error:
return str(error)
except:
load_matlab = None
save_matlab = None
out = sp.io.loadmat(filename, struct_as_record=True)
data = dict()
for (key, value) in out.items():
data[key] = get_matlab_value(value)
return data, None
except Exception as error:
return None, str(error)


try:
import numpy as np # analysis:ignore
def save_matlab(data, filename):
if sp.io is FakeObject:
return

def load_array(filename):
try:
name = osp.splitext(osp.basename(filename))[0]
data = np.load(filename)
if isinstance(data, np.lib.npyio.NpzFile):
return dict(data), None
elif hasattr(data, 'keys'):
return data, None
else:
return {name: data}, None
except Exception as error:
return None, str(error)

def __save_array(data, basename, index):
"""Save numpy array"""
fname = basename + '_%04d.npy' % index
np.save(fname, data)
return fname
except:
load_array = None


try:
from spyder.pil_patch import Image

if sys.byteorder == 'little':
_ENDIAN = '<'
else:
_ENDIAN = '>'
DTYPES = {
"1": ('|b1', None),
"L": ('|u1', None),
"I": ('%si4' % _ENDIAN, None),
"F": ('%sf4' % _ENDIAN, None),
"I;16": ('|u2', None),
"I;16S": ('%si2' % _ENDIAN, None),
"P": ('|u1', None),
"RGB": ('|u1', 3),
"RGBX": ('|u1', 4),
"RGBA": ('|u1', 4),
"CMYK": ('|u1', 4),
"YCbCr": ('|u1', 4),
}
def __image_to_array(filename):
img = Image.open(filename)
try:
dtype, extra = DTYPES[img.mode]
except KeyError:
raise RuntimeError("%s mode is not supported" % img.mode)
shape = (img.size[1], img.size[0])
if extra is not None:
shape += (extra,)
return np.array(img.getdata(), dtype=np.dtype(dtype)).reshape(shape)
try:
sp.io.savemat(filename, data, oned_as='row')
except Exception as error:
return str(error)

def load_image(filename):
try:
name = osp.splitext(osp.basename(filename))[0]
return {name: __image_to_array(filename)}, None
except Exception as error:
return None, str(error)
except:
load_image = None

def load_array(filename):
if np.load is FakeObject:
return None, ''

try:
name = osp.splitext(osp.basename(filename))[0]
data = np.load(filename)
if isinstance(data, np.lib.npyio.NpzFile):
return dict(data), None
elif hasattr(data, 'keys'):
return data, None
else:
return {name: data}, None
except Exception as error:
return None, str(error)


def __save_array(data, basename, index):
"""Save numpy array"""
fname = basename + '_%04d.npy' % index
np.save(fname, data)
return fname


if sys.byteorder == 'little':
_ENDIAN = '<'
else:
_ENDIAN = '>'

DTYPES = {
"1": ('|b1', None),
"L": ('|u1', None),
"I": ('%si4' % _ENDIAN, None),
"F": ('%sf4' % _ENDIAN, None),
"I;16": ('|u2', None),
"I;16S": ('%si2' % _ENDIAN, None),
"P": ('|u1', None),
"RGB": ('|u1', 3),
"RGBX": ('|u1', 4),
"RGBA": ('|u1', 4),
"CMYK": ('|u1', 4),
"YCbCr": ('|u1', 4),
}


def __image_to_array(filename):
img = PIL.Image.open(filename)
try:
dtype, extra = DTYPES[img.mode]
except KeyError:
raise RuntimeError("%s mode is not supported" % img.mode)
shape = (img.size[1], img.size[0])
if extra is not None:
shape += (extra,)
return np.array(img.getdata(), dtype=np.dtype(dtype)).reshape(shape)


def load_image(filename):
if PIL.Image is FakeObject or np.array is FakeObject:
return None, ''

try:
name = osp.splitext(osp.basename(filename))[0]
return {name: __image_to_array(filename)}, None
except Exception as error:
return None, str(error)


def load_pickle(filename):
"""Load a pickle file as a dictionary"""
try:
if pd:
if pd.read_pickle is not FakeObject:
return pd.read_pickle(filename), None
else:
with open(filename, 'rb') as fid:
Expand Down Expand Up @@ -315,13 +294,13 @@ def save_dictionary(data, filename):
raise RuntimeError('No supported objects to save')

saved_arrays = {}
if load_array is not None:
if np.ndarray is not FakeObject:
# Saving numpy arrays with np.save
arr_fname = osp.splitext(filename)[0]
for name in list(data.keys()):
try:
if isinstance(data[name],
np.ndarray) and data[name].size > 0:
if (isinstance(data[name], np.ndarray) and
data[name].size > 0):
# Save arrays at data root
fname = __save_array(data[name], arr_fname,
len(saved_arrays))
Expand All @@ -335,8 +314,8 @@ def save_dictionary(data, filename):
iterator = iter(list(data[name].items()))
to_remove = []
for index, value in iterator:
if isinstance(value,
np.ndarray) and value.size > 0:
if (isinstance(value, np.ndarray) and
value.size > 0):
fname = __save_array(value, arr_fname,
len(saved_arrays))
saved_arrays[(name, index)] = (
Expand Down Expand Up @@ -407,12 +386,12 @@ def load_dictionary(filename):
with open(pickle_filename, 'rb') as fdesc:
data = pickle.loads(fdesc.read())
saved_arrays = {}
if load_array is not None:
if np.load is not FakeObject:
# Loading numpy arrays saved with np.save
try:
saved_arrays = data.pop('__saved_arrays__')
for (name, index), fname in list(saved_arrays.items()):
arr = np.load( osp.join(tmp_folder, fname) )
arr = np.load(osp.join(tmp_folder, fname))
if index is None:
data[name] = arr
elif isinstance(data[name], dict):
Expand Down
Loading