Repository: chainer/chainer

Issue:
Unreadable error message when cuda is not installed in `to_gpu` method`
We need to check availability of CUDA at all methods in `cuda` module

```
>>> import chainer.cuda
>>> chainer.cuda.to_gpu(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/chainer/cuda.py", line 410, in to_gpu
    return gpuarray.to_gpu(array, allocator=mem_alloc)
NameError: global name 'gpuarray' is not defined
```



Discussion:

Resolving patch:
diff --git a/chainer/cuda.py b/chainer/cuda.py
--- a/chainer/cuda.py
+++ b/chainer/cuda.py
@@ -128,6 +128,24 @@ class GPUArray(object):
 _pid = None
 
 
+def _check_cuda_available():
+    if not available:
+        global _resolution_error
+        msg = '''CUDA environment is not correctly set up.
+Use `pip install -U chainer-cuda-deps` to install libraries.
+'''
+
+        # Note that error message depends on its type
+        if isinstance(_resolution_error, pkg_resources.DistributionNotFound):
+            msg += 'Required package is not found: ' + str(_resolution_error)
+        elif isinstance(_resolution_error, pkg_resources.VersionConflict):
+            msg += 'Version conflict: ' + str(_resolution_error)
+        else:
+            msg += 'Unknwon error: ' + str(_resolution_error)
+
+        raise RuntimeError(msg)
+
+
 def init(device=None):
     """Initializes CUDA global state.
 
@@ -155,21 +173,7 @@ def init(device=None):
     """
     global _contexts, _cublas_handles, _generators, _pid, _pools
 
-    if not available:
-        global _resolution_error
-        msg = '''CUDA environment is not correctly set up.
-Use `pip install -U chainer-cuda-deps` to install libraries.
-'''
-
-        # Note that error message depends on its type
-        if isinstance(_resolution_error, pkg_resources.DistributionNotFound):
-            msg += 'Required package is not found: ' + str(_resolution_error)
-        elif isinstance(_resolution_error, pkg_resources.VersionConflict):
-            msg += 'Version conflict: ' + str(_resolution_error)
-        else:
-            msg += 'Unknwon error: ' + str(_resolution_error)
-
-        raise RuntimeError(msg)
+    _check_cuda_available()
 
     pid = os.getpid()
     if _pid == pid:  # already initialized
@@ -204,6 +208,8 @@ def shutdown():
     """
     global _contexts, _cublas_handles, _pid, _pools
 
+    _check_cuda_available()
+
     pid = os.getpid()
     if _pid != pid:  # not initialized
         return
@@ -473,6 +479,7 @@ def to_gpu(array, device=None):
         copy GPUArray into specified device.
 
     """
+    _check_cuda_available()
     if isinstance(array, GPUArray):
         return array
     with using_device(device):
@@ -509,6 +516,7 @@ def to_gpu_async(array, stream=None):
         ``array`` without performing any copy.
 
     """
+    _check_cuda_available()
     if isinstance(array, GPUArray):
         return array
     return gpuarray.to_gpu_async(array, allocator=mem_alloc, stream=stream)
@@ -563,6 +571,7 @@ def empty(shape, dtype=numpy.float32):
         pool.
 
     """
+    _check_cuda_available()
     return gpuarray.empty(shape, dtype, allocator=mem_alloc)
 
 
@@ -605,6 +614,7 @@ def ones(shape, dtype=numpy.float32, stream=None):
 
 def empty_like(array):
     """Alias to :func:`pycuda.gpuarray.empty_like`."""
+    _check_cuda_available()
     return gpuarray.empty_like(array)
 
 


Test patch:
diff --git a/tests/test_cuda.py b/tests/test_cuda.py
--- a/tests/test_cuda.py
+++ b/tests/test_cuda.py
@@ -2,14 +2,12 @@
 import re
 import unittest
 
+import numpy
+
 from chainer import cuda
 from chainer import testing
 
 
-if cuda.available:
-    cuda.init()
-
-
 class TestCuda(unittest.TestCase):
 
     def _get_cuda_deps_requires(self):
@@ -37,5 +35,33 @@ def test_requires(self):
         self.assertSetEqual(set(['chainer'] + cuda._requires),
                             set(requires))
 
+    def test_init_unavailable(self):
+        if not cuda.available:
+            with self.assertRaises(RuntimeError):
+                cuda.init()
+
+    def test_to_gpu_unavailable(self):
+        x = numpy.array([1])
+        if not cuda.available:
+            with self.assertRaises(RuntimeError):
+                cuda.to_gpu(x)
+
+    def test_to_gpu_async_unavailable(self):
+        x = numpy.array([1])
+        if not cuda.available:
+            with self.assertRaises(RuntimeError):
+                cuda.to_gpu_async(x)
+
+    def test_empy_unavailable(self):
+        if not cuda.available:
+            with self.assertRaises(RuntimeError):
+                cuda.empty(())
+
+    def test_empy_like_unavailable(self):
+        x = numpy.array([1])
+        if not cuda.available:
+            with self.assertRaises(RuntimeError):
+                cuda.empty_like(x)
+
 
 testing.run_module(__name__, __file__)