Repository: erikrose/parsimonious

Issue:
Node __eq__ method internal error
`Node`'s `__eq__` method doesn't check the type of the object it's being compared to, which leads to an exception if you try to compare Nodes to non-nodes.  For example, I can do `5 == "hello"` in Python, but if I try `5 == grammar.parse(text)`, I get the following exception:

```
  File "/Users/wiseman/Dropbox/Disney/src/cca_dialogengine/env/lib/python2.7/site-packages/parsimonious/nodes.py", line 90, in __eq__
    self.expr_name == other.expr_name and
AttributeError: 'int' object has no attribute 'expr_name'
```


Discussion:

Patch:
diff --git a/parsimonious/nodes.py b/parsimonious/nodes.py
index a60e7f4..26d873d 100644
--- a/parsimonious/nodes.py
+++ b/parsimonious/nodes.py
@@ -90,8 +90,10 @@ class Node(StrAndRepr):
 
     def __eq__(self, other):
         """Support by-value deep comparison with other nodes for testing."""
-        return (other is not None and
-                self.expr_name == other.expr_name and
+        if not isinstance(other, Node):
+            return NotImplemented
+
+        return (self.expr_name == other.expr_name and
                 self.full_text == other.full_text and
                 self.start == other.start and
                 self.end == other.end and


Test patch:
diff --git a/parsimonious/tests/test_nodes.py b/parsimonious/tests/test_nodes.py
index 404aa36..caf9f68 100644
--- a/parsimonious/tests/test_nodes.py
+++ b/parsimonious/tests/test_nodes.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 from nose import SkipTest
-from nose.tools import eq_, assert_raises
+from nose.tools import eq_, ok_, assert_raises
 
 from parsimonious import Grammar, NodeVisitor, VisitationError, rule
 from parsimonious.nodes import Node
@@ -142,3 +142,9 @@ def test_unwrapped_exceptions():
             raise PrimalScream('This should percolate up!')
 
     assert_raises(PrimalScream, Screamer().parse, 'howdy')
+
+
+def test_node_inequality():
+    node = Node('text', 'o hai', 0, 5)
+    ok_(node != 5)
+    ok_(node != None)