From c6fc57763056cdd88dddf035a3912d70ff0440bf Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Fri, 9 Feb 2018 20:33:12 -0600
Subject: [PATCH] Switch to import-based global language versioning scheme

---
 doc/tutorial.rst               |  1 +
 examples/python/hello-loopy.py |  4 +---
 loopy/kernel/creation.py       | 38 +++++++++++++++++++++++++---------
 loopy/version.py               | 28 +++++++++++++++++++------
 test/test_apps.py              |  2 +-
 test/test_c_execution.py       |  2 +-
 test/test_dg.py                |  2 +-
 test/test_diff.py              |  2 +-
 test/test_domain.py            |  2 +-
 test/test_linalg.py            |  2 +-
 test/test_loopy.py             |  2 +-
 test/test_misc.py              |  2 +-
 test/test_nbody.py             |  2 +-
 test/test_numa_diff.py         |  2 +-
 test/test_reduction.py         |  2 +-
 test/test_scan.py              |  2 +-
 test/test_sem_reagan.py        |  2 +-
 test/test_target.py            |  2 +-
 test/test_transform.py         |  2 +-
 19 files changed, 67 insertions(+), 34 deletions(-)

diff --git a/doc/tutorial.rst b/doc/tutorial.rst
index 7196dad86..7ac506806 100644
--- a/doc/tutorial.rst
+++ b/doc/tutorial.rst
@@ -25,6 +25,7 @@ import a few modules and set up a :class:`pyopencl.Context` and a
 
     >>> import loopy as lp
     >>> lp.set_caching_enabled(False)
+    >>> from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1
 
     >>> from warnings import filterwarnings, catch_warnings
     >>> filterwarnings('error', category=lp.LoopyWarning)
diff --git a/examples/python/hello-loopy.py b/examples/python/hello-loopy.py
index da1273d2b..6fa9b5fd3 100644
--- a/examples/python/hello-loopy.py
+++ b/examples/python/hello-loopy.py
@@ -2,15 +2,13 @@ import numpy as np
 import loopy as lp
 import pyopencl as cl
 import pyopencl.array
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1
 
 # setup
 # -----
 ctx = cl.create_some_context()
 queue = cl.CommandQueue(ctx)
 
-# for make_kernel calls from this file
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
-
 n = 15 * 10**6
 a = cl.array.arange(queue, n, dtype=np.float32)
 
diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py
index c351aa5a0..0daf327f4 100644
--- a/loopy/kernel/creation.py
+++ b/loopy/kernel/creation.py
@@ -1922,10 +1922,12 @@ def make_kernel(domains, instructions, kernel_data=["..."], **kwargs):
         If not given, this value defaults to version **(2017, 2, 1)** and
         a warning will be issued.
 
-        If this is impractical, you may also place a global variable
-        ``LOOPY_KERNEL_LANGUAGE_VERSION`` in the global namespace of the
-        function calling :func:`make_kernel`. If *lang_version* is not
-        explicitly given, that its value will be used.
+        To set the kernel version for all :mod:`loopy` kernels in a (Python) source
+        file, you may simply say::
+
+            from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1
+
+        If *lang_version* is not explicitly given, that version value will be used.
 
         See also :ref:`language-versioning`.
 
@@ -1981,17 +1983,26 @@ def make_kernel(domains, instructions, kernel_data=["..."], **kwargs):
     if lang_version is None:
         # {{{ peek into caller's module to look for LOOPY_KERNEL_LANGUAGE_VERSION
 
+        from loopy.version import LANGUAGE_VERSION_SYMBOLS
+
         # This *is* gross. But it seems like the right thing interface-wise.
         import inspect
         caller_globals = inspect.currentframe().f_back.f_globals
 
-        try:
-            lang_version = caller_globals["LOOPY_KERNEL_LANGUAGE_VERSION"]
-        except KeyError:
-            pass
+        for ver_sym in LANGUAGE_VERSION_SYMBOLS:
+            try:
+                lang_version = caller_globals[ver_sym]
+                break
+            except KeyError:
+                pass
 
         # }}}
 
+        import loopy.version
+        version_to_symbol = dict(
+                (getattr(loopy.version, lvs), lvs)
+                for lvs in LANGUAGE_VERSION_SYMBOLS)
+
         if lang_version is None:
             from warnings import warn
             from loopy.diagnostic import LoopyWarning
@@ -2001,13 +2012,20 @@ def make_kernel(domains, instructions, kernel_data=["..."], **kwargs):
             warn("'lang_version' was not passed to make_kernel(). "
                     "To avoid this warning, pass "
                     "lang_version={ver} in this invocation. "
-                    "(Or set LOOPY_KERNEL_LANGUAGE_VERSION = {ver} in "
+                    "(Or say 'from loopy.version import "
+                    "{sym_ver}' in "
                     "the global scope of the calling frame.)"
-                    .format(ver=MOST_RECENT_LANGUAGE_VERSION),
+                    .format(
+                        ver=MOST_RECENT_LANGUAGE_VERSION,
+                        sym_ver=version_to_symbol[MOST_RECENT_LANGUAGE_VERSION]
+                        ),
                     LoopyWarning, stacklevel=2)
 
             lang_version = FALLBACK_LANGUAGE_VERSION
 
+        if lang_version not in version_to_symbol:
+            raise LoopyError("Language version '%s' is not known." % lang_version)
+
     if lang_version >= (2018, 1):
         options = options.copy(enforce_variable_access_ordered=True)
 
diff --git a/loopy/version.py b/loopy/version.py
index d7b0ebc45..aeb0b277a 100644
--- a/loopy/version.py
+++ b/loopy/version.py
@@ -38,6 +38,14 @@ DATA_MODEL_VERSION = "v77-islpy%s" % _islpy_version
 FALLBACK_LANGUAGE_VERSION = (2017, 2, 1)
 MOST_RECENT_LANGUAGE_VERSION = (2018, 1)
 
+LOOPY_USE_LANGUAGE_VERSION_2018_1 = (2018, 1)
+LOOPY_USE_LANGUAGE_VERSION_2017_2_1 = (2017, 2, 1)
+
+LANGUAGE_VERSION_SYMBOLS = [
+        "LOOPY_USE_LANGUAGE_VERSION_2018_1",
+        "LOOPY_USE_LANGUAGE_VERSION_2017_2_1",
+        ]
+
 __doc__ = """
 
 .. currentmodule:: loopy
@@ -64,10 +72,13 @@ language version to let them take advantage of this check.
 As a result, :mod:`loopy` will now issue a warning when a call to
 :func:`loopy.make_kernel` does not declare a language version. Such kernels
 will (indefinitely) default to language version 2017.2.1.  If passing a
-language version to :func:`make_kernel` is impractical, you may also place a
-global variable ``LOOPY_KERNEL_LANGUAGE_VERSION`` in the global namespace of
-the function calling :func:`make_kernel`. If *lang_version* is not explicitly
-given, this value will be used.
+language version to :func:`make_kernel` is impractical, you may also import
+one of the ``LOOPY_USE_LANGUAGE_VERSION_...`` symbols given below using::
+
+    from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1
+
+in the global namespace of the function calling :func:`make_kernel`. If
+*lang_version* in that call is not explicitly given, this value will be used.
 
 Language versions will generally reflect the version number of :mod:`loopy` in
 which they were introduced, though it is likely that most versions of
@@ -81,11 +92,16 @@ will work hard to avoid backward-incompatible language changes.)
     example **(2018, 1)**. Direct comparison of these tuples will always
     yield valid version comparisons.
 
+
 History of Language Versions
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-* ``(2018, 1)``: :attr:`loopy.Options.enforce_variable_access_ordered`
+.. data:: LOOPY_USE_LANGUAGE_VERSION_2018_1
+
+    :attr:`loopy.Options.enforce_variable_access_ordered`
     is turned on by default.
 
-* ``(2017, 2, 1)``: Initial legacy language version.
+.. data:: LOOPY_USE_LANGUAGE_VERSION_2017_2_1
+
+    Initial legacy language version.
 """
diff --git a/test/test_apps.py b/test/test_apps.py
index 4707b7f07..1be7edec1 100644
--- a/test/test_apps.py
+++ b/test/test_apps.py
@@ -49,7 +49,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 # {{{ convolutions
diff --git a/test/test_c_execution.py b/test/test_c_execution.py
index 582f3a105..f653eb0dc 100644
--- a/test/test_c_execution.py
+++ b/test/test_c_execution.py
@@ -40,7 +40,7 @@ else:
     faulthandler.enable()
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_c_target():
diff --git a/test/test_dg.py b/test/test_dg.py
index 6688362aa..ae725ab49 100644
--- a/test/test_dg.py
+++ b/test/test_dg.py
@@ -34,7 +34,7 @@ from pyopencl.tools import (  # noqa
         pytest_generate_tests_for_pyopencl as pytest_generate_tests)
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_dg_volume(ctx_factory):
diff --git a/test/test_diff.py b/test/test_diff.py
index 8a4fe9587..3d19721ac 100644
--- a/test/test_diff.py
+++ b/test/test_diff.py
@@ -48,7 +48,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_diff(ctx_factory):
diff --git a/test/test_domain.py b/test/test_domain.py
index d8a83007a..680ff2992 100644
--- a/test/test_domain.py
+++ b/test/test_domain.py
@@ -52,7 +52,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_assume(ctx_factory):
diff --git a/test/test_linalg.py b/test/test_linalg.py
index 7eba5facb..accdebc12 100644
--- a/test/test_linalg.py
+++ b/test/test_linalg.py
@@ -62,7 +62,7 @@ def check_float4(result, ref_result):
                 ref_result[comp], result[comp], rtol=1e-3, atol=1e-3), None
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_axpy(ctx_factory):
diff --git a/test/test_loopy.py b/test/test_loopy.py
index 3e1d2a631..b876cdb55 100644
--- a/test/test_loopy.py
+++ b/test/test_loopy.py
@@ -52,7 +52,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_globals_decl_once_with_multi_subprogram(ctx_factory):
diff --git a/test/test_misc.py b/test/test_misc.py
index c1ae6c532..ec14770a9 100644
--- a/test/test_misc.py
+++ b/test/test_misc.py
@@ -32,7 +32,7 @@ import logging
 logger = logging.getLogger(__name__)
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_compute_sccs():
diff --git a/test/test_nbody.py b/test/test_nbody.py
index f231dfd5b..f2a8fc198 100644
--- a/test/test_nbody.py
+++ b/test/test_nbody.py
@@ -34,7 +34,7 @@ import logging
 logger = logging.getLogger(__name__)
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_nbody(ctx_factory):
diff --git a/test/test_numa_diff.py b/test/test_numa_diff.py
index 7bacad75f..a287ad59d 100644
--- a/test/test_numa_diff.py
+++ b/test/test_numa_diff.py
@@ -44,7 +44,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 @pytest.mark.parametrize("Nq", [7])
diff --git a/test/test_reduction.py b/test/test_reduction.py
index 1ddbbfebf..6b62bad5b 100644
--- a/test/test_reduction.py
+++ b/test/test_reduction.py
@@ -49,7 +49,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_nonsense_reduction(ctx_factory):
diff --git a/test/test_scan.py b/test/test_scan.py
index 228453fd8..44903611d 100644
--- a/test/test_scan.py
+++ b/test/test_scan.py
@@ -56,7 +56,7 @@ __all__ = [
 # - scan(a) + scan(b)
 # - test for badly tagged inames
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 @pytest.mark.parametrize("n", [1, 2, 3, 16])
diff --git a/test/test_sem_reagan.py b/test/test_sem_reagan.py
index a92f2b2ab..ecb2352ae 100644
--- a/test/test_sem_reagan.py
+++ b/test/test_sem_reagan.py
@@ -31,7 +31,7 @@ from pyopencl.tools import (  # noqa
         pytest_generate_tests_for_pyopencl as pytest_generate_tests)
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_tim2d(ctx_factory):
diff --git a/test/test_target.py b/test/test_target.py
index 71a2548c1..c143fbbd2 100644
--- a/test/test_target.py
+++ b/test/test_target.py
@@ -52,7 +52,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_ispc_target(occa_mode=False):
diff --git a/test/test_transform.py b/test/test_transform.py
index a234d7ac5..e1a58e302 100644
--- a/test/test_transform.py
+++ b/test/test_transform.py
@@ -49,7 +49,7 @@ __all__ = [
         ]
 
 
-LOOPY_KERNEL_LANGUAGE_VERSION = (2018, 1)
+from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1  # noqa
 
 
 def test_chunk_iname(ctx_factory):
-- 
GitLab