From 562cafc14f66bbad7f76e7600fa0acd71d00194e Mon Sep 17 00:00:00 2001
From: Syrus Akbary <me@syrusakbary.com>
Date: Wed, 21 Mar 2018 21:20:07 -0700
Subject: [PATCH] Fixed str on abstract types. Improved repr

---
 graphene/types/base.py                  |  2 +-
 graphene/types/tests/test_objecttype.py | 25 +++++++++++++++++++------
 graphene/utils/subclass_with_meta.py    | 11 +++++++++--
 3 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/graphene/types/base.py b/graphene/types/base.py
index d9c3bdd4..50242674 100644
--- a/graphene/types/base.py
+++ b/graphene/types/base.py
@@ -21,7 +21,7 @@ class BaseOptions(object):
             raise Exception("Can't modify frozen Options {0}".format(self))
 
     def __repr__(self):
-        return "<{} type={}>".format(self.__class__.__name__, self.class_type.__name__)
+        return "<{} name={}>".format(self.__class__.__name__, repr(self.name))
 
 
 class BaseType(SubclassWithMeta):
diff --git a/graphene/types/tests/test_objecttype.py b/graphene/types/tests/test_objecttype.py
index e7c76d97..73d3823c 100644
--- a/graphene/types/tests/test_objecttype.py
+++ b/graphene/types/tests/test_objecttype.py
@@ -44,6 +44,8 @@ def test_generate_objecttype():
     assert MyObjectType._meta.description == "Documentation"
     assert MyObjectType._meta.interfaces == tuple()
     assert MyObjectType._meta.fields == {}
+    assert repr(
+        MyObjectType) == "<MyObjectType meta=<ObjectTypeOptions name='MyObjectType'>>"
 
 
 def test_generate_objecttype_with_meta():
@@ -65,7 +67,6 @@ def test_generate_lazy_objecttype():
 
     class InnerObjectType(ObjectType):
         field = Field(MyType)
-    
 
     assert MyObjectType._meta.name == "MyObjectType"
     example_field = MyObjectType._meta.fields['example']
@@ -115,7 +116,8 @@ def test_generate_objecttype_inherit_abstracttype():
     assert MyObjectType._meta.interfaces == ()
     assert MyObjectType._meta.name == "MyObjectType"
     assert list(MyObjectType._meta.fields.keys()) == ['field1', 'field2']
-    assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field]
+    assert list(map(type, MyObjectType._meta.fields.values())) == [
+        Field, Field]
 
 
 def test_generate_objecttype_inherit_abstracttype_reversed():
@@ -129,7 +131,8 @@ def test_generate_objecttype_inherit_abstracttype_reversed():
     assert MyObjectType._meta.interfaces == ()
     assert MyObjectType._meta.name == "MyObjectType"
     assert list(MyObjectType._meta.fields.keys()) == ['field1', 'field2']
-    assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field]
+    assert list(map(type, MyObjectType._meta.fields.values())) == [
+        Field, Field]
 
 
 def test_generate_objecttype_unmountedtype():
@@ -145,7 +148,8 @@ def test_parent_container_get_fields():
 
 
 def test_parent_container_interface_get_fields():
-    assert list(ContainerWithInterface._meta.fields.keys()) == ['ifield', 'field1', 'field2']
+    assert list(ContainerWithInterface._meta.fields.keys()) == [
+        'ifield', 'field1', 'field2']
 
 
 def test_objecttype_as_container_only_args():
@@ -182,7 +186,8 @@ def test_objecttype_as_container_invalid_kwargs():
     with pytest.raises(TypeError) as excinfo:
         Container(unexisting_field="3")
 
-    assert "'unexisting_field' is an invalid keyword argument for Container" == str(excinfo.value)
+    assert "'unexisting_field' is an invalid keyword argument for Container" == str(
+        excinfo.value)
 
 
 def test_objecttype_container_benchmark(benchmark):
@@ -238,7 +243,6 @@ def test_objecttype_no_fields_output():
         def resolve_user(self, info):
             return User()
 
-
     schema = Schema(query=Query)
     result = schema.execute(''' query basequery {
         user {
@@ -252,3 +256,12 @@ def test_objecttype_no_fields_output():
             'name': None,
         }
     }
+
+
+def test_abstract_objecttype_can_str():
+    class MyObjectType(ObjectType):
+        class Meta:
+            abstract = True
+        field = MyScalar()
+
+    assert str(MyObjectType) == "MyObjectType"
diff --git a/graphene/utils/subclass_with_meta.py b/graphene/utils/subclass_with_meta.py
index 9226e418..61205be0 100644
--- a/graphene/utils/subclass_with_meta.py
+++ b/graphene/utils/subclass_with_meta.py
@@ -6,9 +6,15 @@ from .props import props
 
 
 class SubclassWithMeta_Meta(InitSubclassMeta):
+    _meta = None
+
+    def __str__(cls):
+        if cls._meta:
+            return cls._meta.name
+        return cls.__name__
 
     def __repr__(cls):
-        return cls._meta.name
+        return "<{} meta={}>".format(cls.__name__, repr(cls._meta))
 
 
 class SubclassWithMeta(six.with_metaclass(SubclassWithMeta_Meta)):
@@ -24,7 +30,8 @@ class SubclassWithMeta(six.with_metaclass(SubclassWithMeta_Meta)):
             elif isclass(_Meta):
                 _meta_props = props(_Meta)
             else:
-                raise Exception("Meta have to be either a class or a dict. Received {}".format(_Meta))
+                raise Exception(
+                    "Meta have to be either a class or a dict. Received {}".format(_Meta))
             delattr(cls, "Meta")
         options = dict(meta_options, **_meta_props)