From 7192fcfebc793c2db6ce2ec3659410f58f1e7fea Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 02:31:46 +0200 Subject: [PATCH 1/8] pipenv integration work --- anaconda_lib/helpers.py | 58 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index 4bf799cb..33eeced3 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -198,6 +198,10 @@ def get_settings(view, name, default=None): """Get settings """ + if name not in ['anaconda_linting_behaviour', 'anaconda_linter_delay', 'anaconda_linting']: + print('\n\n\nget_settings', name, default) + + global ENVIRON_HOOK_INVALID if view is None: @@ -209,10 +213,15 @@ def get_settings(view, name, default=None): ENVIRON_HOOK_INVALID[view.id()]): if view.window() is not None and view.window().folders(): dirname = view.window().folders()[0] + print('dirname', dirname) while True: environfile = os.path.join(dirname, '.anaconda') - if os.path.exists(environfile) and os.path.isfile(environfile): - # print("Environ found on %s" % environfile) + pipfile = os.path.join(dirname, 'Pipfile') + print('\n\n\nAnaconda\n\n\n') + print(pipfile) + + if os.path.isfile(environfile): + print("Environ found on %s" % environfile) with open(environfile, 'r') as jsonfile: try: data = json.loads(jsonfile.read()) @@ -242,6 +251,51 @@ def get_settings(view, name, default=None): ) return r + + elif name == 'python_interpreter' and os.path.isfile(pipfile): + try: + # check if venv has been created + sp = create_subprocess( + ['pipenv', '--venv'], cwd=dirname, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + _, sp_err = sp.communicate() + if sp_err or sp.returncode: + pipenv_error = "Pipenv's error was: \n{}".format(sp_err.decode().strip()) + raise Exception(pipenv_error) + + # get Python interpreter + sp = create_subprocess( + ['pipenv', '--py'], cwd=dirname, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + sp_out, sp_err = sp.communicate() + sp_out = sp_out.strip() + if sp_err or sp.returncode: + pipenv_error = "Pipenv's error was: \n{}".format(sp_err.decode().strip()) + raise Exception(pipenv_error) + if not os.path.isfile(sp_out.strip()): + pipenv_error = "Pipenv's Python interpreter is not valid: \n{}".format(sp_out) + raise Exception(pipenv_error) + + sublime.error_message(repr(sp_out)) + return sp_out + + except Exception as error: + sublime.error_message( + "Anaconda Message:\n" + "I found an Pipfile in {pipfile} " + "path but couldn't get the virtual environment " + "using pipenv.\n\n" + "{pipenv_error}\n\n" + "That means that your Pipfile " + "is being ignored.".format( + pipfile=pipfile, pipenv_error=error, + ) + ) + logging.error(error) + ENVIRON_HOOK_INVALID[view.id()] = True + break # stop loop + + else: parts = os.path.split(dirname) if len(parts[1]) > 0: From 614d3bff1fdaa7d8c8cdd4a8946b6dde1c3f65a6 Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 16:17:48 +0200 Subject: [PATCH 2/8] settings cache --- anaconda_lib/helpers.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index 33eeced3..0956a471 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -34,6 +34,7 @@ ENVIRON_HOOK_INVALID = defaultdict(lambda: False) AUTO_COMPLETION_DOT_VIEWS = [] +SETTINGS_CACHE = {} def dot_completion(view): @@ -198,10 +199,6 @@ def get_settings(view, name, default=None): """Get settings """ - if name not in ['anaconda_linting_behaviour', 'anaconda_linter_delay', 'anaconda_linting']: - print('\n\n\nget_settings', name, default) - - global ENVIRON_HOOK_INVALID if view is None: @@ -211,6 +208,11 @@ def get_settings(view, name, default=None): if (name in ('python_interpreter', 'extra_paths') and not ENVIRON_HOOK_INVALID[view.id()]): + + settings_key = '{}_{}_{}'.format(view.id(), name, default) + if settings_key in SETTINGS_CACHE: + return SETTINGS_CACHE[settings_key] + if view.window() is not None and view.window().folders(): dirname = view.window().folders()[0] print('dirname', dirname) @@ -246,13 +248,16 @@ def get_settings(view, name, default=None): ) w = view.window() if w is not None: - return sublime.expand_variables( + SETTINGS_CACHE[settings_key] = sublime.expand_variables( r, w.extract_variables() ) + return SETTINGS_CACHE[settings_key] - return r + SETTINGS_CACHE[settings_key] = r + return SETTINGS_CACHE[settings_key] elif name == 'python_interpreter' and os.path.isfile(pipfile): + print("Pipfile found on %s" % pipfile) try: # check if venv has been created sp = create_subprocess( @@ -277,7 +282,8 @@ def get_settings(view, name, default=None): raise Exception(pipenv_error) sublime.error_message(repr(sp_out)) - return sp_out + SETTINGS_CACHE[settings_key] = sp_out + return SETTINGS_CACHE[settings_key] except Exception as error: sublime.error_message( @@ -303,6 +309,9 @@ def get_settings(view, name, default=None): else: break # stop loop + SETTINGS_CACHE[settings_key] = None + return SETTINGS_CACHE[settings_key] + r = view.settings().get(name, plugin_settings.get(name, default)) if name == 'python_interpreter': r = expand(view, r) From fcda48b4bb9202e99d94b3a928409c55f63dd28e Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 16:18:30 +0200 Subject: [PATCH 3/8] removed print lines --- anaconda_lib/helpers.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index 0956a471..06e71adb 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -219,11 +219,9 @@ def get_settings(view, name, default=None): while True: environfile = os.path.join(dirname, '.anaconda') pipfile = os.path.join(dirname, 'Pipfile') - print('\n\n\nAnaconda\n\n\n') - print(pipfile) if os.path.isfile(environfile): - print("Environ found on %s" % environfile) + # print("Environ found on %s" % environfile) with open(environfile, 'r') as jsonfile: try: data = json.loads(jsonfile.read()) @@ -257,7 +255,7 @@ def get_settings(view, name, default=None): return SETTINGS_CACHE[settings_key] elif name == 'python_interpreter' and os.path.isfile(pipfile): - print("Pipfile found on %s" % pipfile) + # print("Pipfile found on %s" % pipfile) try: # check if venv has been created sp = create_subprocess( From d06f21c545609446a0544446db3f02a748a0b082 Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 16:30:32 +0200 Subject: [PATCH 4/8] print lines removed --- anaconda_lib/helpers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index 06e71adb..e560c1be 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -215,7 +215,6 @@ def get_settings(view, name, default=None): if view.window() is not None and view.window().folders(): dirname = view.window().folders()[0] - print('dirname', dirname) while True: environfile = os.path.join(dirname, '.anaconda') pipfile = os.path.join(dirname, 'Pipfile') @@ -279,7 +278,6 @@ def get_settings(view, name, default=None): pipenv_error = "Pipenv's Python interpreter is not valid: \n{}".format(sp_out) raise Exception(pipenv_error) - sublime.error_message(repr(sp_out)) SETTINGS_CACHE[settings_key] = sp_out return SETTINGS_CACHE[settings_key] From 22ed6ae6f6b4206e14be1b45a67969e3609bfbdf Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 19:17:25 +0200 Subject: [PATCH 5/8] better cache --- anaconda_lib/helpers.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index e560c1be..eae0e1c8 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -204,6 +204,8 @@ def get_settings(view, name, default=None): if view is None: return default + print('get_settings', view.id(), name, default) + plugin_settings = sublime.load_settings('Anaconda.sublime-settings') if (name in ('python_interpreter', 'extra_paths') and not @@ -211,16 +213,21 @@ def get_settings(view, name, default=None): settings_key = '{}_{}_{}'.format(view.id(), name, default) if settings_key in SETTINGS_CACHE: + print('settings found in cache', settings_key, SETTINGS_CACHE) return SETTINGS_CACHE[settings_key] + print('settings not found in cache', settings_key, SETTINGS_CACHE) + if view.window() is not None and view.window().folders(): dirname = view.window().folders()[0] while True: + print('dirname', dirname) environfile = os.path.join(dirname, '.anaconda') pipfile = os.path.join(dirname, 'Pipfile') if os.path.isfile(environfile): # print("Environ found on %s" % environfile) + sublime.error_message("Environ found on %s" % environfile) with open(environfile, 'r') as jsonfile: try: data = json.loads(jsonfile.read()) @@ -251,35 +258,35 @@ def get_settings(view, name, default=None): return SETTINGS_CACHE[settings_key] SETTINGS_CACHE[settings_key] = r - return SETTINGS_CACHE[settings_key] + return r elif name == 'python_interpreter' and os.path.isfile(pipfile): # print("Pipfile found on %s" % pipfile) + sublime.error_message("Pipfile found on %s" % pipfile) try: # check if venv has been created sp = create_subprocess( ['pipenv', '--venv'], cwd=dirname, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - _, sp_err = sp.communicate() + _, sp_err = [p.decode().strip() for p in sp.communicate()] if sp_err or sp.returncode: - pipenv_error = "Pipenv's error was: \n{}".format(sp_err.decode().strip()) + pipenv_error = "Pipenv's error was: \n{}".format(sp_err) raise Exception(pipenv_error) # get Python interpreter sp = create_subprocess( ['pipenv', '--py'], cwd=dirname, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - sp_out, sp_err = sp.communicate() - sp_out = sp_out.strip() + sp_out, sp_err = [p.decode().strip() for p in sp.communicate()] if sp_err or sp.returncode: - pipenv_error = "Pipenv's error was: \n{}".format(sp_err.decode().strip()) + pipenv_error = "Pipenv's error was: \n{}".format(sp_err) raise Exception(pipenv_error) - if not os.path.isfile(sp_out.strip()): + if not os.path.isfile(sp_out): pipenv_error = "Pipenv's Python interpreter is not valid: \n{}".format(sp_out) raise Exception(pipenv_error) SETTINGS_CACHE[settings_key] = sp_out - return SETTINGS_CACHE[settings_key] + return sp_out except Exception as error: sublime.error_message( @@ -305,8 +312,6 @@ def get_settings(view, name, default=None): else: break # stop loop - SETTINGS_CACHE[settings_key] = None - return SETTINGS_CACHE[settings_key] r = view.settings().get(name, plugin_settings.get(name, default)) if name == 'python_interpreter': @@ -317,6 +322,9 @@ def get_settings(view, name, default=None): else: r = expand(view, r) + if name in ['python_interpreter', 'extra_paths']: + SETTINGS_CACHE[settings_key] = r + return r @@ -343,6 +351,7 @@ def is_remote_session(view): """Returns True if we are in a remote session """ + print('is_remote_session', type(get_interpreter(view)), repr(get_interpreter(view))) if '://' in get_interpreter(view): return True From f3e2f38a617b7fe6a12c558581926fdc2bb44995 Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 19:21:48 +0200 Subject: [PATCH 6/8] pipfile cache --- anaconda_lib/helpers.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index eae0e1c8..0ce886f1 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -35,6 +35,7 @@ ENVIRON_HOOK_INVALID = defaultdict(lambda: False) AUTO_COMPLETION_DOT_VIEWS = [] SETTINGS_CACHE = {} +PIPFILE_CACHE = {} def dot_completion(view): @@ -204,8 +205,6 @@ def get_settings(view, name, default=None): if view is None: return default - print('get_settings', view.id(), name, default) - plugin_settings = sublime.load_settings('Anaconda.sublime-settings') if (name in ('python_interpreter', 'extra_paths') and not @@ -213,21 +212,21 @@ def get_settings(view, name, default=None): settings_key = '{}_{}_{}'.format(view.id(), name, default) if settings_key in SETTINGS_CACHE: - print('settings found in cache', settings_key, SETTINGS_CACHE) + # print('settings found in cache', settings_key, SETTINGS_CACHE) return SETTINGS_CACHE[settings_key] - print('settings not found in cache', settings_key, SETTINGS_CACHE) + # print('settings not found in cache', settings_key, SETTINGS_CACHE) if view.window() is not None and view.window().folders(): dirname = view.window().folders()[0] while True: - print('dirname', dirname) + # print('dirname', dirname) environfile = os.path.join(dirname, '.anaconda') pipfile = os.path.join(dirname, 'Pipfile') if os.path.isfile(environfile): # print("Environ found on %s" % environfile) - sublime.error_message("Environ found on %s" % environfile) + # sublime.error_message("Environ found on %s" % environfile) with open(environfile, 'r') as jsonfile: try: data = json.loads(jsonfile.read()) @@ -261,8 +260,11 @@ def get_settings(view, name, default=None): return r elif name == 'python_interpreter' and os.path.isfile(pipfile): + if pipfile in PIPFILE_CACHE: + # print('pipfile found in cache', pipfile) + return PIPFILE_CACHE[pipfile] # print("Pipfile found on %s" % pipfile) - sublime.error_message("Pipfile found on %s" % pipfile) + # sublime.error_message("Pipfile found on %s" % pipfile) try: # check if venv has been created sp = create_subprocess( @@ -285,6 +287,7 @@ def get_settings(view, name, default=None): pipenv_error = "Pipenv's Python interpreter is not valid: \n{}".format(sp_out) raise Exception(pipenv_error) + PIPFILE_CACHE[pipfile] = sp_out SETTINGS_CACHE[settings_key] = sp_out return sp_out @@ -351,7 +354,6 @@ def is_remote_session(view): """Returns True if we are in a remote session """ - print('is_remote_session', type(get_interpreter(view)), repr(get_interpreter(view))) if '://' in get_interpreter(view): return True From 7d1870a3c7ee5b79cf732bfc3ecdf1b1a87db141 Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 20:03:57 +0200 Subject: [PATCH 7/8] smarter caching --- anaconda_lib/helpers.py | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index 0ce886f1..377eee41 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -13,7 +13,6 @@ import functools import traceback import subprocess -from collections import defaultdict import sublime @@ -32,7 +31,6 @@ NOT_SCRATCH = 0x02 LINTING_ENABLED = 0x04 -ENVIRON_HOOK_INVALID = defaultdict(lambda: False) AUTO_COMPLETION_DOT_VIEWS = [] SETTINGS_CACHE = {} PIPFILE_CACHE = {} @@ -200,22 +198,18 @@ def get_settings(view, name, default=None): """Get settings """ - global ENVIRON_HOOK_INVALID - if view is None: return default plugin_settings = sublime.load_settings('Anaconda.sublime-settings') - if (name in ('python_interpreter', 'extra_paths') and not - ENVIRON_HOOK_INVALID[view.id()]): - + if name in ['python_interpreter', 'extra_paths']: settings_key = '{}_{}_{}'.format(view.id(), name, default) if settings_key in SETTINGS_CACHE: - # print('settings found in cache', settings_key, SETTINGS_CACHE) + print('settings found in cache', settings_key, SETTINGS_CACHE) return SETTINGS_CACHE[settings_key] - # print('settings not found in cache', settings_key, SETTINGS_CACHE) + print('settings not found in cache', settings_key, SETTINGS_CACHE) if view.window() is not None and view.window().folders(): dirname = view.window().folders()[0] @@ -241,7 +235,6 @@ def get_settings(view, name, default=None): ) ) logging.error(error) - ENVIRON_HOOK_INVALID[view.id()] = True break # stop loop else: r = data.get( @@ -259,21 +252,28 @@ def get_settings(view, name, default=None): SETTINGS_CACHE[settings_key] = r return r - elif name == 'python_interpreter' and os.path.isfile(pipfile): + elif name == 'python_interpreter' and os.path.isfile(pipfile) and \ + PIPFILE_CACHE.get(pipfile) != 'ERROR': + if pipfile in PIPFILE_CACHE: - # print('pipfile found in cache', pipfile) + print('pipfile found in cache', pipfile) return PIPFILE_CACHE[pipfile] # print("Pipfile found on %s" % pipfile) # sublime.error_message("Pipfile found on %s" % pipfile) try: - # check if venv has been created - sp = create_subprocess( - ['pipenv', '--venv'], cwd=dirname, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - _, sp_err = [p.decode().strip() for p in sp.communicate()] + try: + # check if venv has been created + sp = create_subprocess( + ['pipenv', '--venv'], cwd=dirname, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + _, sp_err = [p.decode().strip() for p in sp.communicate()] + + except Exception: + raise Exception("Pipenv is not installed, please " + "install Pipenv to enable pipfile support") + if sp_err or sp.returncode: - pipenv_error = "Pipenv's error was: \n{}".format(sp_err) - raise Exception(pipenv_error) + raise Exception("Pipenv's error was: \n{}".format(sp_err)) # get Python interpreter sp = create_subprocess( @@ -304,7 +304,7 @@ def get_settings(view, name, default=None): ) ) logging.error(error) - ENVIRON_HOOK_INVALID[view.id()] = True + PIPFILE_CACHE[pipfile] = 'ERROR' break # stop loop @@ -315,7 +315,6 @@ def get_settings(view, name, default=None): else: break # stop loop - r = view.settings().get(name, plugin_settings.get(name, default)) if name == 'python_interpreter': r = expand(view, r) From 76bfc9426de1d3f88afee31775a676d194737bf8 Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Fri, 27 Oct 2017 20:09:15 +0200 Subject: [PATCH 8/8] commented out print lines --- anaconda_lib/helpers.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/anaconda_lib/helpers.py b/anaconda_lib/helpers.py index 377eee41..8597ceaa 100644 --- a/anaconda_lib/helpers.py +++ b/anaconda_lib/helpers.py @@ -206,10 +206,9 @@ def get_settings(view, name, default=None): if name in ['python_interpreter', 'extra_paths']: settings_key = '{}_{}_{}'.format(view.id(), name, default) if settings_key in SETTINGS_CACHE: - print('settings found in cache', settings_key, SETTINGS_CACHE) + # print('settings found in cache', settings_key, SETTINGS_CACHE) return SETTINGS_CACHE[settings_key] - - print('settings not found in cache', settings_key, SETTINGS_CACHE) + # print('settings not found in cache', settings_key, SETTINGS_CACHE) if view.window() is not None and view.window().folders(): dirname = view.window().folders()[0] @@ -256,7 +255,7 @@ def get_settings(view, name, default=None): PIPFILE_CACHE.get(pipfile) != 'ERROR': if pipfile in PIPFILE_CACHE: - print('pipfile found in cache', pipfile) + # print('pipfile found in cache', pipfile) return PIPFILE_CACHE[pipfile] # print("Pipfile found on %s" % pipfile) # sublime.error_message("Pipfile found on %s" % pipfile)