internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: dmlc/dgl

Issue:
HAN example error on version 0.4.2
get the below error running HAN example on version 0.4.2,  version 0.4.1 works though

AttributeError: '<class 'dgl.heterograph_index.HeteroGraphIndex'>' object has no attribute 'get_immutable_gidx'



Discussion:
@mufeili 
@BarclayII @yzh119 It seems that the use of [`get_immutable_gidx`](https://github.com/dmlc/dgl/blob/master/python/dgl/nn/pytorch/softmax.py#L52) in `edge_softmax` as of PR #1139 breaks the use of `edge_softmax` for `DGLHeteroGraph`. What's the recommended way to fix it?

Also the documentation of `get_immutable_gidx` should be updated as it says this function should only be used for scheduler.

Resolving patch:
diff --git a/python/dgl/nn/pytorch/softmax.py b/python/dgl/nn/pytorch/softmax.py
--- a/python/dgl/nn/pytorch/softmax.py
+++ b/python/dgl/nn/pytorch/softmax.py
@@ -6,6 +6,8 @@
 from ...base import ALL, is_all
 from ... import backend as F
 from ... import utils
+from ...graph import DGLGraph
+from ...heterograph import DGLHeteroGraph
 
 __all__ = ['edge_softmax']
 
@@ -49,7 +51,19 @@ def forward(ctx, g, score, eids):
 
         n_nodes = g.number_of_nodes()
         n_edges = g.number_of_edges()
-        gidx = g._graph.get_immutable_gidx(utils.to_dgl_context(score.device))
+
+        # TODO(BarclayII): this is a temporary fix of memory leakage in PyTorch
+        # in PR #1139.  We should investigate further on what was actually happening
+        # when implementing EdgeSoftmax with message passing API instead of
+        # operators.
+        score_context = utils.to_dgl_context(score.device)
+        if isinstance(g, DGLGraph):
+            gidx = g._graph.get_immutable_gidx(score_context)
+        elif isinstance(g, DGLHeteroGraph):
+            assert g._graph.number_of_etypes() == 1, \
+                "EdgeSoftmax only support one edge type"
+            gidx = g._graph.get_unitgraph(0, score_context)
+
         ctx.backward_cache = n_nodes, n_edges, gidx
 
         #g.update_all(fn.copy_e('s', 'm'), fn.max('m', 'smax'))


Test patch:
Repository: dmlc/dgl

Issue:
AttributeError: module 'dgl.nn' has no attribute 'pytorch'
## 🐛 Bug

When I try to use some of the predefined modules of dgl by the following code, I encounter an error: AttributeError: module 'dgl.nn' has no attribute 'pytorch'.

Similar problems also happen to other backends, including TensorFlow and MXNet.

## To Reproduce

Steps to reproduce the behavior:

```python
import dgl.nn
# or import dgl
c = dgl.nn.pytorch.conv.GraphConv(10,2)
```

## Expected behavior

The code should generate a GraphConv layer without any error.

## Environment

 - DGL Version (e.g., 1.0): 0.4.2
 - Backend Library & Version (e.g., PyTorch 0.4.1, MXNet/Gluon 1.3): Pytorch 1.4.0
 - OS (e.g., Linux): Irrelelevent 
 - How you installed DGL (`conda`, `pip`, source): conda
 - Build command you used (if compiling from source):
 - Python version: 3.7
 - CUDA/cuDNN version (if applicable): Irrelelevent 
 - GPU models and configuration (e.g. V100): Irrelelevent 
 - Any other relevant information:

## Additional context

I read the source code and **found the reason and solution** to this problem.

### Reason:

The `__init__.py` file of `dgl/nn` is empty. Therefore, if i import dgl or dgl.nn, python cannot automatically find files of its sub-directories.

I verified it by the following code:
```python
import dgl.nn.python
c = dgl.nn.pytorch.conv.GraphConv(10,2)
```
It works fine.

### Solution:

Add 3 lines of code like `from . import pytorch` into file `dgl/nn/__init__.py` for PyTorch and the other 2 backends.
It is better to automatically detect the backend library and import the correct sub-directory.


Discussion:
> Add 3 lines of code like `from . import pytorch` into file `dgl/nn/__init__.py` for PyTorch and the other 2 backends.
> It is better to automatically detect the backend library and import the correct sub-directory.

I would prefer the latter solution.  The former solution would require all backends to be installed.

Resolving patch:
diff --git a/python/dgl/__init__.py b/python/dgl/__init__.py
--- a/python/dgl/__init__.py
+++ b/python/dgl/__init__.py
@@ -8,7 +8,6 @@
 from .backend import load_backend
 
 from . import function
-from . import nn
 from . import contrib
 from . import container
 from . import random
diff --git a/python/dgl/nn/__init__.py b/python/dgl/nn/__init__.py
--- a/python/dgl/nn/__init__.py
+++ b/python/dgl/nn/__init__.py
@@ -1 +1,12 @@
 """Package for neural network common components."""
+import importlib
+import sys
+from ..backend import backend_name
+
+def _load_backend(mod_name):
+    mod = importlib.import_module('.%s' % mod_name, __name__)
+    thismod = sys.modules[__name__]
+    for api, obj in mod.__dict__.items():
+        setattr(thismod, api, obj)
+
+_load_backend(backend_name)


Test patch:
Repository: dmlc/dgl

Issue:
Loading dataset PROTEINS leads to IndexError
## 🐛 Bug

<!-- A clear and concise description of what the bug is. -->
When loading dataset PROTEINS using function `LegacyTUDataset()`, raise `IndexError: too many indices for array`
## To Reproduce

Steps to reproduce the behavior:

```python
from dgl.data import LegacyTUDataset

dataset = LegacyTUDataset(name='PROTEINS')
 ```
The error message as following:
```
~/opt/anaconda3/lib/python3.7/site-packages/dgl/data/tu.py in __init__(self, name, use_pandas, hidden_size, max_allow_node)
     78                 self._file_path("node_attributes"), delimiter=",")
     79             for idxs, g in zip(node_idx_list, self.graph_lists):
---> 80                 g.ndata['feat'] = DS_node_attr[idxs, :]
     81             self.data_mode = "node_attr"
     82         except IOError:

IndexError: too many indices for array
```
<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->

## Expected behavior

<!-- A clear and concise description of what you expected to happen. -->
Successfully loading PROTEINS dataset
## Environment

 - DGL Version (e.g., 1.0): 0.4.2
 - Backend Library & Version (e.g., PyTorch 0.4.1, MXNet/Gluon 1.3): PyTorch
 - OS (e.g., Linux): MacOS X
 - How you installed DGL (`conda`, `pip`, source): pip
 - Build command you used (if compiling from source):
 - Python version: 3.7
 - CUDA/cuDNN version (if applicable):
 - GPU models and configuration (e.g. V100):
 - Any other relevant information:

## Additional context

<!-- Add any other context about the problem here. -->



Discussion:

Resolving patch:
diff --git a/python/dgl/data/tu.py b/python/dgl/data/tu.py
--- a/python/dgl/data/tu.py
+++ b/python/dgl/data/tu.py
@@ -75,6 +75,8 @@ def __init__(self, name, use_pandas=False,
         try:
             DS_node_attr = np.loadtxt(
                 self._file_path("node_attributes"), delimiter=",")
+            if DS_node_attr.ndim == 1:
+                DS_node_attr = np.expand_dims(DS_node_attr, -1)
             for idxs, g in zip(node_idx_list, self.graph_lists):
                 g.ndata['feat'] = DS_node_attr[idxs, :]
             self.data_mode = "node_attr"


Test patch:
Repository: dmlc/dgl

Issue:
Split tensor equally for multi gpu
<!-- A clear and concise description of what the bug is. -->
When we run this example demo https://github.com/dmlc/dgl/blob/master/examples/pytorch/graphsage/train_sampling_multi_gpu.py to enable multi gpu graphsage training, we found there exists a mirror error that is located at line148. 
![图片](https://user-images.githubusercontent.com/42287875/89497424-e7d67000-d7ee-11ea-864d-28f8068a245d.png)
Actually, its split result would drop some training data. For Example, if we have a tensor and the split logic is same as the example demo:
![图片](https://user-images.githubusercontent.com/42287875/89497007-0851fa80-d7ee-11ea-9e9f-36859e7bdb84.png)
The split result would be as follow and as you can see the final tensor element 8 is dropped.
![图片](https://user-images.githubusercontent.com/42287875/89497129-4bac6900-d7ee-11ea-9e4b-0d3402758e94.png)

What we expected is to change the split logic as follow:
![图片](https://user-images.githubusercontent.com/42287875/89497194-726a9f80-d7ee-11ea-8fcb-65878037b684.png)
Now the split result is:
![图片](https://user-images.githubusercontent.com/42287875/89497224-81515200-d7ee-11ea-9d90-3fd58a674397.png)
This time, all the training tensor would be loaded to its corresponding GPU to be trained.

Our Environment：
- DGL Version (master branch)


Discussion:
You are right. Thanks for your report!

Resolving patch:
diff --git a/examples/pytorch/graphsage/train_cv_multi_gpu.py b/examples/pytorch/graphsage/train_cv_multi_gpu.py
--- a/examples/pytorch/graphsage/train_cv_multi_gpu.py
+++ b/examples/pytorch/graphsage/train_cv_multi_gpu.py
@@ -11,6 +11,7 @@
 import argparse
 import tqdm
 import traceback
+import math
 from _thread import start_new_thread
 from functools import wraps
 from dgl.data import RedditDataset
@@ -267,7 +268,7 @@ def run(proc_id, n_gpus, args, devices, data):
     val_mask = th.BoolTensor(val_mask)
 
     # Split train_nid
-    train_nid = th.split(train_nid, len(train_nid) // n_gpus)[proc_id]
+    train_nid = th.split(train_nid, math.ceil(len(train_nid) // n_gpus))[proc_id]
 
     # Create sampler
     sampler = NeighborSampler(g, [int(_) for _ in args.fan_out.split(',')])
diff --git a/examples/pytorch/graphsage/train_sampling_multi_gpu.py b/examples/pytorch/graphsage/train_sampling_multi_gpu.py
--- a/examples/pytorch/graphsage/train_sampling_multi_gpu.py
+++ b/examples/pytorch/graphsage/train_sampling_multi_gpu.py
@@ -9,6 +9,7 @@
 import dgl.function as fn
 import dgl.nn.pytorch as dglnn
 import time
+import math
 import argparse
 from dgl.data import RedditDataset
 from torch.nn.parallel import DistributedDataParallel
@@ -145,7 +146,7 @@ def run(proc_id, n_gpus, args, devices, data):
     test_nid = test_mask.nonzero()[:, 0]
 
     # Split train_nid
-    train_nid = th.split(train_nid, len(train_nid) // n_gpus)[proc_id]
+    train_nid = th.split(train_nid, math.ceil(len(train_nid) // n_gpus))[proc_id]
 
     # Create PyTorch DataLoader for constructing blocks
     sampler = dgl.sampling.MultiLayerNeighborSampler(


Test patch:
Repository: dmlc/dgl

Issue:
jtnn example error
NOCUDA=1 python3 vaetrain_dgl.py
it shows NameError: name 'tensor' is not defined in dgl/examples/pytorch/jtnn/jtnn/nnutils.py", line 11, in cuda
    return tensor

env: 
dgl 0.5.3
torch 1.7.1
mac os





Discussion:

Resolving patch:
diff --git a/examples/pytorch/jtnn/jtnn/nnutils.py b/examples/pytorch/jtnn/jtnn/nnutils.py
--- a/examples/pytorch/jtnn/jtnn/nnutils.py
+++ b/examples/pytorch/jtnn/jtnn/nnutils.py
@@ -8,7 +8,7 @@ def cuda(x):
     if torch.cuda.is_available() and not os.getenv('NOCUDA', None):
         return x.to(torch.device('cuda'))   # works for both DGLGraph and tensor
     else:
-        return tensor
+        return x
 
 
 class GRUUpdate(nn.Module):


Test patch:
Repository: dmlc/dgl

Issue:
Clarify link prediction docs
## 📚 Documentation

<!-- Please specify whether it's tutorial part or API reference part--> Tutorial part
<!-- Describe the issue.-->
On your new tutorial about [link prediction](https://docs.dgl.ai/en/latest/new-tutorial/4_link_predict.html), you stated that it followed [SEAL model](https://papers.nips.cc/paper/2018/file/53f0d7c537d99b3824f0f99d62ea2428-Paper.pdf), but what was represented there is just simply applying score function after message passing, which is quite different from SEAL. More particular, SEAL model does not use node feature but node labeling instead, which allows it to apply to inductive setting. Node labeling also requires constructing a local subgraph for each pair of nodes beforehand, then message passing on these graphs, which is really computationally inefficient, and quite difficult to implement.


Discussion:
Hi, I think the tutorial follows the practice of SEAL on formulating a link prediction problem as a binary classification problem and the way SEAL prepares positive/negative samples. Yes, I agree we should be more precise on the statement.

Resolving patch:
diff --git a/tutorials/blitz/4_link_predict.py b/tutorials/blitz/4_link_predict.py
--- a/tutorials/blitz/4_link_predict.py
+++ b/tutorials/blitz/4_link_predict.py
@@ -37,9 +37,7 @@
 # either citing or being cited, between two papers exists in a citation
 # network.
 #
-# This tutorial follows a relatively simple practice from
-# `SEAL <https://papers.nips.cc/paper/2018/file/53f0d7c537d99b3824f0f99d62ea2428-Paper.pdf>`__.
-# It formulates the link prediction problem as a binary classification
+# This tutorial formulates the link prediction problem as a binary classification
 # problem as follows:
 #
 # -  Treat the edges in the graph as *positive examples*.
@@ -50,6 +48,12 @@
 # -  Evaluate the model with any binary classification metric such as Area
 #    Under Curve (AUC).
 #
+# .. note::
+#
+#    The practice comes from
+#    `SEAL <https://papers.nips.cc/paper/2018/file/53f0d7c537d99b3824f0f99d62ea2428-Paper.pdf>`__,
+#    although the model here does not use their idea of node labeling.
+#
 # In some domains such as large-scale recommender systems or information
 # retrieval, you may favor metrics that emphasize good performance of
 # top-K predictions. In these cases you may want to consider other metrics


Test patch:
Repository: dmlc/dgl

Issue:
Error select_topk with idtype int32 graph
## 🐛 Bug

<!-- A clear and concise description of what the bug is. -->

dgl.sampling.select_topk raises error with a graph created by option of `idtype=tf.int32`.

## To Reproduce

Steps to reproduce the behavior:

```python
u, v = tf.constant([0,0,0,1]), tf.constant([1,2,3,4])
g = dgl.graph((u, v), idtype=tf.int32)
g = dgl.to_simple(g, return_counts="w")
g = dgl.sampling.select_topk(g, 3, "w")
```

<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->
> DGLError: Expect argument "nodes["_N"]" to have data type <dtype: 'int32'> and device context /cpu:0. But got <dtype: 'int64'> and /cpu:0.


## Expected behavior

<!-- A clear and concise description of what you expected to happen. -->

## Environment

 - DGL Version (e.g., 1.0): 0.5.3
 - Backend Library & Version (e.g., PyTorch 0.4.1, MXNet/Gluon 1.3): tf 2.4.1
 - OS (e.g., Linux): Ubuntu 18.04
 - How you installed DGL (`conda`, `pip`, source): pip
 - Build command you used (if compiling from source): 
 - Python version: 3.7
 - CUDA/cuDNN version (if applicable): 11.0
 - GPU models and configuration (e.g. V100):
 - Any other relevant information:

## Additional context

<!-- Add any other context about the problem here. -->



Discussion:

Resolving patch:
diff --git a/python/dgl/sampling/neighbor.py b/python/dgl/sampling/neighbor.py
--- a/python/dgl/sampling/neighbor.py
+++ b/python/dgl/sampling/neighbor.py
@@ -252,7 +252,10 @@ def select_topk(g, k, weight, nodes=None, edge_dir='in', ascending=False,
     """
     # Rectify nodes to a dictionary
     if nodes is None:
-        nodes = {ntype: F.arange(0, g.number_of_nodes(ntype)) for ntype in g.ntypes}
+        nodes = {
+            ntype: F.astype(F.arange(0, g.number_of_nodes(ntype)), g.idtype)
+            for ntype in g.ntypes
+        }
     elif not isinstance(nodes, dict):
         if len(g.ntypes) > 1:
             raise DGLError("Must specify node type when the graph is not homogeneous.")


Test patch:
Repository: dmlc/dgl

Issue:
HGT implementation bug?
https://github.com/dmlc/dgl/blob/master/examples/pytorch/hgt/model.py#L81

The implemented hgt set value of nodes multiple times when calculating by different edge attention, which will cause the `nodes["v"]` of earlier etype be overwritten by later one. 


Discussion:

Resolving patch:
diff --git a/examples/pytorch/hgt/model.py b/examples/pytorch/hgt/model.py
--- a/examples/pytorch/hgt/model.py
+++ b/examples/pytorch/hgt/model.py
@@ -78,7 +78,7 @@ def forward(self, G, h):
 
                 sub_graph.srcdata['k'] = k
                 sub_graph.dstdata['q'] = q
-                sub_graph.srcdata['v'] = v
+                sub_graph.srcdata['v_%d' % e_id] = v
 
                 sub_graph.apply_edges(fn.v_dot_u('q', 'k', 't'))
                 attn_score = sub_graph.edata.pop('t').sum(-1) * relation_pri / self.sqrt_dk
@@ -86,8 +86,8 @@ def forward(self, G, h):
 
                 sub_graph.edata['t'] = attn_score.unsqueeze(-1)
 
-            G.multi_update_all({etype : (fn.u_mul_e('v', 't', 'm'), fn.sum('m', 't')) \
-                                for etype in edge_dict}, cross_reducer = 'mean')
+            G.multi_update_all({etype : (fn.u_mul_e('v_%d' % e_id, 't', 'm'), fn.sum('m', 't')) \
+                                for etype, e_id in edge_dict.items()}, cross_reducer = 'mean')
 
             new_h = {}
             for ntype in G.ntypes:


Test patch:
Repository: dmlc/dgl

Issue:
reverse_edge_ids  in EdgeDataLoader versus reverse_eids in EdgeCollator
Thanks for the great library!

dgl.dataloading.pytorch.EdgeDataLoader accepts the keyword argument **reverse_edge_ids**. 
https://docs.dgl.ai/api/python/dgl.dataloading.html

dgl.dataloading.EdgeCollator however requires **reverse_eids**.
https://docs.dgl.ai/api/python/dgl.dataloading.html#dgl.dataloading.EdgeCollator

Maybe you can adjust this naming discrepancy. Moreover, I would suggest updating the documentation of the "reverse_eids". It sounds like it requires a mapping "eid to reverse eid", while in fact, it takes a list of reverse eids which should be in the same order as the non-reversed eids.

Cheers and keep up the great work!


Discussion:

Resolving patch:
diff --git a/python/dgl/dataloading/dataloader.py b/python/dgl/dataloading/dataloader.py
--- a/python/dgl/dataloading/dataloader.py
+++ b/python/dgl/dataloading/dataloader.py
@@ -453,7 +453,11 @@ class EdgeCollator(Collator):
 
         If ``g_sampling`` is given, ``exclude`` is ignored and will be always ``None``.
     reverse_eids : Tensor or dict[etype, Tensor], optional
-        The mapping from original edge ID to its reverse edge ID.
+        A tensor of reverse edge ID mapping.  The i-th element indicates the ID of
+        the i-th edge's reverse edge.
+
+        If the graph is heterogeneous, this argument requires a dictionary of edge
+        types and the reverse edge ID mapping tensors.
 
         Required and only used when ``exclude`` is set to ``reverse_id``.
 
diff --git a/python/dgl/dataloading/pytorch/__init__.py b/python/dgl/dataloading/pytorch/__init__.py
--- a/python/dgl/dataloading/pytorch/__init__.py
+++ b/python/dgl/dataloading/pytorch/__init__.py
@@ -317,8 +317,12 @@ class EdgeDataLoader:
 
         See the description of the argument with the same name in the docstring of
         :class:`~dgl.dataloading.EdgeCollator` for more details.
-    reverse_edge_ids : Tensor or dict[etype, Tensor], optional
-        The mapping from the original edge IDs to the ID of their reverse edges.
+    reverse_eids : Tensor or dict[etype, Tensor], optional
+        A tensor of reverse edge ID mapping.  The i-th element indicates the ID of
+        the i-th edge's reverse edge.
+
+        If the graph is heterogeneous, this argument requires a dictionary of edge
+        types and the reverse edge ID mapping tensors.
 
         See the description of the argument with the same name in the docstring of
         :class:`~dgl.dataloading.EdgeCollator` for more details.


Test patch:
Repository: dmlc/dgl

Issue:
Moving a graph to GPU will change the default CUDA device
## 🐛 Bug

<!-- A clear and concise description of what the bug is. -->

## To Reproduce
```
import torch
import dgl

torch.cuda.set_device(1)
print(torch.cuda.current_device())  # print 1
device = 'cuda'  # 'cuda:1'
g = dgl.graph((torch.tensor([0, 1, 2]), torch.tensor([1, 2, 3]))).to(device)
print(torch.cuda.current_device())  # print 0
```

<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->

## Expected behavior
 The index of the current device should not be changed.
<!-- A clear and concise description of what you expected to happen. -->

## Environment

 - DGL Version (e.g., 1.0): 0.6
 - Backend Library & Version (e.g., PyTorch 0.4.1, MXNet/Gluon 1.3): PyTorch 1.9.0a0+gitaeaa91b
 - OS (e.g., Linux): RHEL
 - How you installed DGL (`conda`, `pip`, source): source
 - Build command you used (if compiling from source):
 - Python version: 3.8
 - CUDA/cuDNN version (if applicable): 11.0
 - GPU models and configuration (e.g. V100): NVIDIA GeForce RTX 2080 Ti
 - Any other relevant information:

## Additional context

<!-- Add any other context about the problem here. -->



Discussion:

Resolving patch:
diff --git a/python/dgl/backend/pytorch/tensor.py b/python/dgl/backend/pytorch/tensor.py
--- a/python/dgl/backend/pytorch/tensor.py
+++ b/python/dgl/backend/pytorch/tensor.py
@@ -86,7 +86,7 @@ def device_type(ctx):
 def device_id(ctx):
     ctx = th.device(ctx)
     if ctx.index is None:
-        return 0
+        return 0 if ctx.type == 'cpu' else th.cuda.current_device()
     else:
         return ctx.index
 


Test patch:
Repository: dmlc/dgl

Issue:
Remove `DGLGraph.__len__` completly
## 🚀 Feature
`DGLGraph.__len__` is currently deprecated and a warning is issued if its accessed, while that is per se not problematic, its one hell of a nuisance if you work with certain debuggers. (In my case: PyCharm) Reason being that pycharm wants to display the length of objects in the current scope in the "variable view" and thus calls `__len__` every time you modify anything, resulting in this warning to be printed to the console any time you do virtually anything:
```
/redacted/python3.9/site-packages/dgl/base.py:45: DGLWarning: DGLGraph.__len__ is deprecated.Please directly call DGLGraph.number_of_nodes.
  return warnings.warn(message, category=category, stacklevel=1)
``` 
## Motivation

I am always annoyed by this when I use the pycharm debugger with dgl, which is 90% of my workflow. I use pycharm + its debugger like other people use jupyter notebooks.

## Alternatives

After some further digging I found out about pythons [warnings.filterwarnings](https://docs.python.org/3/library/warnings.html#warnings.filterwarnings) which can be used for this case like so:
```
import warnings

warnings.filterwarnings("ignore", message="DGLGraph\.__len__")
```

## Pitch

Drop `DGLGraph.__len__`, preferably in the next release.


Discussion:

Resolving patch:
diff --git a/python/dgl/heterograph.py b/python/dgl/heterograph.py
--- a/python/dgl/heterograph.py
+++ b/python/dgl/heterograph.py
@@ -2447,13 +2447,6 @@ def num_edges(self, etype=None):
         else:
             return self._graph.number_of_edges(self.get_etype_id(etype))
 
-    def __len__(self):
-        """Deprecated: please directly call :func:`number_of_nodes`
-        """
-        dgl_warning('DGLGraph.__len__ is deprecated.'
-                    'Please directly call DGLGraph.number_of_nodes.')
-        return self.number_of_nodes()
-
     @property
     def is_multigraph(self):
         """Return whether the graph is a multigraph with parallel edges.
diff --git a/tutorials/models/1_gnn/4_rgcn.py b/tutorials/models/1_gnn/4_rgcn.py
--- a/tutorials/models/1_gnn/4_rgcn.py
+++ b/tutorials/models/1_gnn/4_rgcn.py
@@ -313,7 +313,7 @@ def forward(self, g):
 g.edata.update({'rel_type': edge_type, 'norm': edge_norm})
 
 # create model
-model = Model(len(g),
+model = Model(g.num_nodes(),
               n_hidden,
               num_classes,
               num_rels,


Test patch:
diff --git a/tests/compute/test_graph.py b/tests/compute/test_graph.py
--- a/tests/compute/test_graph.py
+++ b/tests/compute/test_graph.py
@@ -59,7 +59,6 @@ def test_query():
     def _test_one(g):
         assert g.number_of_nodes() == 10
         assert g.number_of_edges() == 20
-        assert len(g) == 10
 
         for i in range(10):
             assert g.has_node(i)
@@ -131,7 +130,6 @@ def _test(g):
     def _test_csr_one(g):
         assert g.number_of_nodes() == 10
         assert g.number_of_edges() == 20
-        assert len(g) == 10
 
         for i in range(10):
             assert g.has_node(i)