Repository: chainer/chainer

Issue:
`Variable.__repr__` raises error when underlying data is not initialized
In v2, the following code raises an error.

```
In [1]: import chainer
In [2]: a = chainer.Variable()
In [4]: a.data is None
Out[4]: True
In [5]: repr(a)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-f35fccf361ee> in <module>()
----> 1 repr(a)

/Users/oonokenta/dev/chainer/chainer/variable.py in __repr__(self)
    305 
    306     def __repr__(self):
--> 307         return variable_repr(self)
    308 
    309     def __str__(self):

/Users/oonokenta/dev/chainer/chainer/variable.py in variable_repr(var)
     75         prefix = 'variable'
     76 
---> 77     if arr.size > 0 or arr.shape == (0,):
     78         lst = numpy.array2string(arr, None, None, None, ', ', prefix + '(')
     79     else:  # show zero-length shape unless it is (0,)

AttributeError: 'NoneType' object has no attribute 'size'
```

It is because `variable_repr(var)` assumes that  `var.data` is not `None`.



Discussion:

Resolving patch:
diff --git a/chainer/variable.py b/chainer/variable.py
--- a/chainer/variable.py
+++ b/chainer/variable.py
@@ -75,10 +75,13 @@ def variable_repr(var):
     else:
         prefix = 'variable'
 
-    if arr.size > 0 or arr.shape == (0,):
+    if arr is None:
+        lst = 'None'
+    elif arr.size > 0 or arr.shape == (0,):
         lst = numpy.array2string(arr, None, None, None, ', ', prefix + '(')
     else:  # show zero-length shape unless it is (0,)
         lst = '[], shape=%s' % (repr(arr.shape),)
+
     return '%s(%s)' % (prefix, lst)
 
 
@@ -94,12 +97,18 @@ def variable_str(var):
         arr = var.data
     else:
         arr = var.data.get()
+
     if var.name:
-        prefix = 'variable ' + var.name + '('
+        prefix = 'variable ' + var.name
+    else:
+        prefix = 'variable'
+
+    if arr is None:
+        lst = 'None'
     else:
-        prefix = 'variable('
-    return (prefix + numpy.array2string(arr, None, None, None, ' ', prefix) +
-            ')')
+        lst = numpy.array2string(arr, None, None, None, ' ', prefix + '(')
+
+    return '%s(%s)' % (prefix, lst)
 
 
 class VariableNode(object):


Test patch:
diff --git a/tests/chainer_tests/test_variable.py b/tests/chainer_tests/test_variable.py
--- a/tests/chainer_tests/test_variable.py
+++ b/tests/chainer_tests/test_variable.py
@@ -1137,6 +1137,8 @@ def test_backward_gpu(self):
 
 
 @testing.parameterize(
+    {'x_shape': None, 'dtype': None, 'repr': 'variable(None)',
+     'str': 'variable(None)'},
     {'x_shape': (2, 2,), 'dtype': np.float16,
      'repr': 'variable([[ 0.,  1.],\n          [ 2.,  3.]])',
      'str': 'variable([[ 0.  1.]\n          [ 2.  3.]])'},
@@ -1152,10 +1154,13 @@ def test_backward_gpu(self):
 class TestUnnamedVariableToString(unittest.TestCase):
 
     def setUp(self):
-        x = np.empty(self.x_shape)
-        x = np.arange(x.size).reshape(self.x_shape)
-        x = x.astype(self.dtype)
-        self.x = chainer.Variable(x)
+        if self.x_shape is None:
+            self.x = chainer.Variable()
+        else:
+            x = np.empty(self.x_shape)
+            x = np.arange(x.size).reshape(self.x_shape)
+            x = x.astype(self.dtype)
+            self.x = chainer.Variable(x)
 
     def test_repr_cpu(self):
         self.assertEqual(repr(self.x), self.repr)
@@ -1205,6 +1210,8 @@ def test_str_gpu(self):
 
 
 @testing.parameterize(
+    {'x_shape': None, 'dtype': None, 'repr': 'variable x(None)',
+     'str': 'variable x(None)'},
     {'x_shape': (2, 2,), 'dtype': np.float32,
      'repr': 'variable x([[ 0.,  1.],\n            [ 2.,  3.]])',
      'str': 'variable x([[ 0.  1.]\n            [ 2.  3.]])'},
@@ -1214,10 +1221,13 @@ def test_str_gpu(self):
 class TestNamedVariableToString(unittest.TestCase):
 
     def setUp(self):
-        x = np.empty(self.x_shape)
-        x = np.arange(x.size).reshape(self.x_shape)
-        x = x.astype(self.dtype)
-        self.x = chainer.Variable(x, name='x')
+        if self.x_shape is None:
+            self.x = chainer.Variable(name='x')
+        else:
+            x = np.empty(self.x_shape)
+            x = np.arange(x.size).reshape(self.x_shape)
+            x = x.astype(self.dtype)
+            self.x = chainer.Variable(x, name='x')
 
     def test_named_repr(self):
         self.assertEqual(repr(self.x), self.repr)