From 43183fbae90bf22fbc76083c2b4a2334ef05f113 Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Tue, 24 Sep 2019 14:15:34 -0400 Subject: [PATCH 01/14] enh: update to provide bad version info to users --- .et | 3 +++ nipype/__init__.py | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 .et diff --git a/.et b/.et new file mode 100644 index 0000000000..96ed9287ea --- /dev/null +++ b/.et @@ -0,0 +1,3 @@ +{ "bad_versions" : [ "1.2.1", + "1.2.3"] +} \ No newline at end of file diff --git a/nipype/__init__.py b/nipype/__init__.py index 8d135bf061..ba0d708a93 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -63,12 +63,17 @@ def get_info(): if config.getboolean('execution', 'check_version'): import etelemetry - latest = {"version": 'Unknown'} + latest = {"version": 'Unknown', "bad_versions": []} try: - latest = etelemetry.get_project("nipy/nipype") + latest.update(**etelemetry.get_project("nipy/nipype")) except Exception as e: logger.warning("Could not check for version updates: \n%s", e) finally: logger.info(INIT_MSG(packname='nipype', version=__version__, latest=latest["version"])) + if latest["bad_versions"] and \ + any([LooseVersion(__version__) == LooseVersion(ver) + for ver in latest["bad_versions"]): + logger.critical(('You are using a version of Nipype with a critical ' + 'bug. Please use a different version.')) From ae2dddf21b4713888f2687097c6373935e391060 Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Tue, 24 Sep 2019 15:04:40 -0400 Subject: [PATCH 02/14] use result to determine output --- nipype/__init__.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index ba0d708a93..091d8ec33c 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -64,16 +64,19 @@ def get_info(): import etelemetry latest = {"version": 'Unknown', "bad_versions": []} + result = None try: - latest.update(**etelemetry.get_project("nipy/nipype")) + result = etelemetry.get_project("nipy/nipype") except Exception as e: logger.warning("Could not check for version updates: \n%s", e) finally: - logger.info(INIT_MSG(packname='nipype', - version=__version__, - latest=latest["version"])) - if latest["bad_versions"] and \ - any([LooseVersion(__version__) == LooseVersion(ver) - for ver in latest["bad_versions"]): - logger.critical(('You are using a version of Nipype with a critical ' - 'bug. Please use a different version.')) + if result: + latest.update(**result) + logger.info(INIT_MSG(packname='nipype', + version=__version__, + latest=latest["version"])) + if latest["bad_versions"] and \ + any([LooseVersion(__version__) == LooseVersion(ver) + for ver in latest["bad_versions"]): + logger.critical(('You are using a version of Nipype with a critical ' + 'bug. Please use a different version.')) From d8411c1b977a93f5b5488914d5ecf64fc1289123 Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Tue, 24 Sep 2019 15:19:14 -0400 Subject: [PATCH 03/14] enh: only display if versions are different --- nipype/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 091d8ec33c..e0ab50477a 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -72,9 +72,10 @@ def get_info(): finally: if result: latest.update(**result) - logger.info(INIT_MSG(packname='nipype', - version=__version__, - latest=latest["version"])) + if LooseVersion(__version__) != LooseVersion(latest["version"]): + logger.info(INIT_MSG(packname='nipype', + version=__version__, + latest=latest["version"])) if latest["bad_versions"] and \ any([LooseVersion(__version__) == LooseVersion(ver) for ver in latest["bad_versions"]): From 861e52c24aa370997e9d9498dcee8dbabb60e35a Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Tue, 24 Sep 2019 15:24:45 -0400 Subject: [PATCH 04/14] fix: syntax error --- nipype/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index e0ab50477a..47895518c4 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -78,6 +78,6 @@ def get_info(): latest=latest["version"])) if latest["bad_versions"] and \ any([LooseVersion(__version__) == LooseVersion(ver) - for ver in latest["bad_versions"]): + for ver in latest["bad_versions"]]): logger.critical(('You are using a version of Nipype with a critical ' 'bug. Please use a different version.')) From 72964f450a2a98fdb8cade6b9ded47a017f62495 Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Tue, 24 Sep 2019 16:14:12 -0400 Subject: [PATCH 05/14] ref: make version checking it's own function --- nipype/__init__.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 47895518c4..419f1701b8 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -22,9 +22,7 @@ config = NipypeConfig() logging = Logging(config) -logger = logging.getLogger('nipype.utils') -INIT_MSG = "Running {packname} version {version} (latest: {latest})".format class NipypeTester(object): def __call__(self, doctests=True, parallel=False): @@ -60,8 +58,18 @@ def get_info(): Rename, Function, Select, Merge) -if config.getboolean('execution', 'check_version'): +def check_version(raise_exception=False): + """Check for the latest version of the library + + parameters: + raise_exception: boolean + Raise a RuntimeError if a bad version is being used + """ + import etelemetry + logger = logging.getLogger('nipype.utils') + + INIT_MSG = "Running {packname} version {version} (latest: {latest})".format latest = {"version": 'Unknown', "bad_versions": []} result = None @@ -77,7 +85,15 @@ def get_info(): version=__version__, latest=latest["version"])) if latest["bad_versions"] and \ - any([LooseVersion(__version__) == LooseVersion(ver) - for ver in latest["bad_versions"]]): - logger.critical(('You are using a version of Nipype with a critical ' - 'bug. Please use a different version.')) + any([LooseVersion(__version__) == LooseVersion(ver) + for ver in latest["bad_versions"]]): + message = ('You are using a version of Nipype with a critical ' + 'bug. Please use a different version.') + if raise_exception: + raise RuntimeError(message) + else: + logger.critical(message) + + +if config.getboolean('execution', 'check_version'): + check_version() From d86fa7816278882cd4557aea7b5665ebf0f1ec6e Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Thu, 26 Sep 2019 16:24:52 -0400 Subject: [PATCH 06/14] ENH: Run memoized check_version at REPL import, Node/Workflow/Interface init --- nipype/__init__.py | 7 ++++++- nipype/interfaces/base/core.py | 4 ++++ nipype/pipeline/engine/base.py | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 419f1701b8..799e92e750 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -5,6 +5,7 @@ absolute_import) import os +import functools from distutils.version import LooseVersion from .info import (LONG_DESCRIPTION as __doc__, URL as __url__, STATUS as @@ -58,6 +59,7 @@ def get_info(): Rename, Function, Select, Merge) +@functools.lru_cache() def check_version(raise_exception=False): """Check for the latest version of the library @@ -95,5 +97,8 @@ def check_version(raise_exception=False): logger.critical(message) +# Run telemetry on import for interactive sessions, such as IPython, Jupyter notebooks, Python REPL if config.getboolean('execution', 'check_version'): - check_version() + import __main__ + if not hasattr(__main__, '__file__'): + check_version() diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 7ba8486082..7132f7fc97 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -169,6 +169,10 @@ class BaseInterface(Interface): def __init__(self, from_file=None, resource_monitor=None, ignore_exception=False, **inputs): + if config.getboolean('execution', 'check_version'): + from ... import check_version + check_version() + if not self.input_spec: raise Exception( 'No input_spec in class: %s' % self.__class__.__name__) diff --git a/nipype/pipeline/engine/base.py b/nipype/pipeline/engine/base.py index 7f7afd3928..ffb64222d4 100644 --- a/nipype/pipeline/engine/base.py +++ b/nipype/pipeline/engine/base.py @@ -41,6 +41,9 @@ def __init__(self, name=None, base_dir=None): self.base_dir = base_dir self.config = deepcopy(config._sections) + if config.getboolean('execution', 'check_version'): + from ... import check_version + check_version() @property def name(self): From 43669cc5b6baf17f3d2d07edc62faefeca1899f8 Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Sun, 29 Sep 2019 22:09:30 -0400 Subject: [PATCH 07/14] fix: use lru_cache in py3 --- nipype/__init__.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 799e92e750..4da4a250b2 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -6,6 +6,7 @@ import os import functools +import sys from distutils.version import LooseVersion from .info import (LONG_DESCRIPTION as __doc__, URL as __url__, STATUS as @@ -59,7 +60,16 @@ def get_info(): Rename, Function, Select, Merge) -@functools.lru_cache() +def sys_based_cache(condition): + def decorator(func): + if not condition: + return func + else: + return functools.lru_cache(func) + return decorator + + +@sys_based_cache(sys.version >= 3) def check_version(raise_exception=False): """Check for the latest version of the library From cf72c26f8e622ffbb7a8f84b9da497860da6d27f Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Sun, 29 Sep 2019 22:33:24 -0400 Subject: [PATCH 08/14] fix: version checking --- nipype/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 4da4a250b2..6fa4579f77 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -62,14 +62,14 @@ def get_info(): def sys_based_cache(condition): def decorator(func): - if not condition: + if condition: return func else: return functools.lru_cache(func) return decorator -@sys_based_cache(sys.version >= 3) +@sys_based_cache(sys.version_info < (3,)) def check_version(raise_exception=False): """Check for the latest version of the library From f614ab90069eafaec11e2813153f1226786b13a1 Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Sun, 29 Sep 2019 23:27:36 -0400 Subject: [PATCH 09/14] fix: decorator and ref: check name --- nipype/__init__.py | 8 ++++---- nipype/interfaces/base/core.py | 4 ++-- nipype/pipeline/engine/base.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 6fa4579f77..ba5ac84624 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -65,12 +65,12 @@ def decorator(func): if condition: return func else: - return functools.lru_cache(func) + return functools.lru_cache()(func) return decorator @sys_based_cache(sys.version_info < (3,)) -def check_version(raise_exception=False): +def check_latest_version(raise_exception=False): """Check for the latest version of the library parameters: @@ -105,10 +105,10 @@ def check_version(raise_exception=False): raise RuntimeError(message) else: logger.critical(message) - + return latest # Run telemetry on import for interactive sessions, such as IPython, Jupyter notebooks, Python REPL if config.getboolean('execution', 'check_version'): import __main__ if not hasattr(__main__, '__file__'): - check_version() + check_latest_version() diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 7132f7fc97..2b885d796e 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -170,8 +170,8 @@ class BaseInterface(Interface): def __init__(self, from_file=None, resource_monitor=None, ignore_exception=False, **inputs): if config.getboolean('execution', 'check_version'): - from ... import check_version - check_version() + from ... import check_latest_version + check_latest_version() if not self.input_spec: raise Exception( diff --git a/nipype/pipeline/engine/base.py b/nipype/pipeline/engine/base.py index ffb64222d4..c1215e4995 100644 --- a/nipype/pipeline/engine/base.py +++ b/nipype/pipeline/engine/base.py @@ -42,8 +42,8 @@ def __init__(self, name=None, base_dir=None): self.base_dir = base_dir self.config = deepcopy(config._sections) if config.getboolean('execution', 'check_version'): - from ... import check_version - check_version() + from ... import check_latest_version + check_latest_version() @property def name(self): From 9c5d64bfb18a7325b702aad1f40adfcd6a730e7f Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Mon, 30 Sep 2019 21:31:41 -0400 Subject: [PATCH 10/14] enh: memoize with global --- nipype/__init__.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index ba5ac84624..5ea3a2a5cd 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -59,17 +59,8 @@ def get_info(): from .interfaces import (DataGrabber, DataSink, SelectFiles, IdentityInterface, Rename, Function, Select, Merge) +etelemetry_results = {} -def sys_based_cache(condition): - def decorator(func): - if condition: - return func - else: - return functools.lru_cache()(func) - return decorator - - -@sys_based_cache(sys.version_info < (3,)) def check_latest_version(raise_exception=False): """Check for the latest version of the library @@ -77,6 +68,8 @@ def check_latest_version(raise_exception=False): raise_exception: boolean Raise a RuntimeError if a bad version is being used """ + if raise_exception in etelemetry_results: + return etelemetry_results[raise_exception] import etelemetry logger = logging.getLogger('nipype.utils') @@ -105,6 +98,7 @@ def check_latest_version(raise_exception=False): raise RuntimeError(message) else: logger.critical(message) + etelemetry_results[raise_exception] = latest return latest # Run telemetry on import for interactive sessions, such as IPython, Jupyter notebooks, Python REPL From 7646796c121e8a188140bbc768f4f0a2a5ad836b Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Wed, 2 Oct 2019 15:17:05 -0400 Subject: [PATCH 11/14] use a class field limit rerunning check --- nipype/interfaces/base/core.py | 4 +++- nipype/pipeline/engine/base.py | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 2b885d796e..8c5c250286 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -166,12 +166,14 @@ class BaseInterface(Interface): _redirect_x = False references_ = [] resource_monitor = True # Enabled for this interface IFF enabled in the config + check_version = None def __init__(self, from_file=None, resource_monitor=None, ignore_exception=False, **inputs): if config.getboolean('execution', 'check_version'): from ... import check_latest_version - check_latest_version() + if BaseInterface.check_version is None: + BaseInterface.check_version = check_latest_version() if not self.input_spec: raise Exception( diff --git a/nipype/pipeline/engine/base.py b/nipype/pipeline/engine/base.py index c1215e4995..7f7afd3928 100644 --- a/nipype/pipeline/engine/base.py +++ b/nipype/pipeline/engine/base.py @@ -41,9 +41,6 @@ def __init__(self, name=None, base_dir=None): self.base_dir = base_dir self.config = deepcopy(config._sections) - if config.getboolean('execution', 'check_version'): - from ... import check_latest_version - check_latest_version() @property def name(self): From f5bec393466bc2b45b6bc221ed5f372f72befc2c Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Wed, 2 Oct 2019 15:19:15 -0400 Subject: [PATCH 12/14] store checked version in baseinterface --- nipype/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 5ea3a2a5cd..59481d9069 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -105,4 +105,5 @@ def check_latest_version(raise_exception=False): if config.getboolean('execution', 'check_version'): import __main__ if not hasattr(__main__, '__file__'): - check_latest_version() + from .interfaces.base import BaseInterface + BaseInterface.check_version = check_latest_version() From e9f553ef6d87d0285fd7d72983ca5d750e6d7ebb Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Wed, 2 Oct 2019 16:09:27 -0400 Subject: [PATCH 13/14] address review comments --- nipype/__init__.py | 12 ++++-------- nipype/interfaces/base/core.py | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 59481d9069..26653916f7 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -5,8 +5,6 @@ absolute_import) import os -import functools -import sys from distutils.version import LooseVersion from .info import (LONG_DESCRIPTION as __doc__, URL as __url__, STATUS as @@ -59,7 +57,6 @@ def get_info(): from .interfaces import (DataGrabber, DataSink, SelectFiles, IdentityInterface, Rename, Function, Select, Merge) -etelemetry_results = {} def check_latest_version(raise_exception=False): """Check for the latest version of the library @@ -68,9 +65,6 @@ def check_latest_version(raise_exception=False): raise_exception: boolean Raise a RuntimeError if a bad version is being used """ - if raise_exception in etelemetry_results: - return etelemetry_results[raise_exception] - import etelemetry logger = logging.getLogger('nipype.utils') @@ -98,7 +92,8 @@ def check_latest_version(raise_exception=False): raise RuntimeError(message) else: logger.critical(message) - etelemetry_results[raise_exception] = latest + else: + latest = None return latest # Run telemetry on import for interactive sessions, such as IPython, Jupyter notebooks, Python REPL @@ -106,4 +101,5 @@ def check_latest_version(raise_exception=False): import __main__ if not hasattr(__main__, '__file__'): from .interfaces.base import BaseInterface - BaseInterface.check_version = check_latest_version() + if BaseInterface._etelemetry_version_data is None: + BaseInterface._etelemetry_version_data = check_latest_version() diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 8c5c250286..85cad50045 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -166,14 +166,14 @@ class BaseInterface(Interface): _redirect_x = False references_ = [] resource_monitor = True # Enabled for this interface IFF enabled in the config - check_version = None + _etelemetry_version_data = None def __init__(self, from_file=None, resource_monitor=None, ignore_exception=False, **inputs): if config.getboolean('execution', 'check_version'): from ... import check_latest_version - if BaseInterface.check_version is None: - BaseInterface.check_version = check_latest_version() + if BaseInterface._etelemetry_version_data is None: + BaseInterface._etelemetry_version_data = check_latest_version() if not self.input_spec: raise Exception( From fcbf57bed077f99e2c8b4fce8b492b0416e2bc13 Mon Sep 17 00:00:00 2001 From: Satrajit Ghosh Date: Wed, 2 Oct 2019 16:12:59 -0400 Subject: [PATCH 14/14] fix: allow networks without internet to check only once --- nipype/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 26653916f7..821a411009 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -92,8 +92,6 @@ def check_latest_version(raise_exception=False): raise RuntimeError(message) else: logger.critical(message) - else: - latest = None return latest # Run telemetry on import for interactive sessions, such as IPython, Jupyter notebooks, Python REPL