Repository: qutebrowser/qutebrowser

Issue:
Add a nice __repr__ to configtypes
Objects in the `config/configtypes.py` module should have a nice `__repr__` function defined (which prints sub-types, attributes, etc.) to ease debugging.


Discussion:
@The-Compiler  can I work on this 
@IcePinguin Sure, please go ahead! The idea is that showing a config type in the debugger (or logs) shows options which are passed via `__init__` - you can use `utils.get_repr` to simplify this, see other places where a `__repr__` is defined. If you need more information, please let me know!
@The-Compiler 
Hello. Seeing as nobody has done a Pull Request on this yet,  I too would like to try myself on this. 
Yet I have several questions:

-  Using `utils.get_repr` Should the representation be in constructor form ? (  `'Foo(one=1, two=2)'` instead of  `'<Foo one=1 two=2>`  ?) 
-  If a variable is set to a (default) value by the super constructor do I need to include it into the representation of the subclass ? 
- Should private members of a class also be displayed ?

Resolving patch:
diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py
--- a/qutebrowser/config/configtypes.py
+++ b/qutebrowser/config/configtypes.py
@@ -316,6 +316,9 @@ def complete(self) -> _Completions:
                 out.append((val, desc))
             return out
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok)
+
 
 class MappingType(BaseType):
 
@@ -341,6 +344,10 @@ def to_py(self, value: typing.Any) -> typing.Any:
         self._validate_valid_values(value.lower())
         return self.MAPPING[value.lower()]
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok,
+                              valid_values=self.valid_values)
+
 
 class String(BaseType):
 
@@ -423,6 +430,14 @@ def complete(self) -> _Completions:
         else:
             return super().complete()
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok,
+                              valid_values=self.valid_values,
+                              minlen=self.minlen,
+                              maxlen=self.maxlen, forbidden=self.forbidden,
+                              completions=self._completions,
+                              encoding=self.encoding)
+
 
 class UniqueCharString(String):
 
@@ -527,6 +542,10 @@ def to_doc(self, value: typing.List, indent: int = 0) -> str:
                 self.valtype.to_doc(elem, indent=indent+1)))
         return '\n'.join(lines)
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok, valtype=self.valtype,
+                              length=self.length)
+
 
 class ListOrValue(BaseType):
 
@@ -599,6 +618,9 @@ def to_doc(self, value: typing.Any, indent: int = 0) -> str:
         val, typ = self._val_and_type(value)
         return typ.to_doc(val)
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok, valtype=self.valtype)
+
 
 class FlagList(List):
 
@@ -652,6 +674,11 @@ def complete(self) -> _Completions:
                 out.append((json.dumps(combination), ''))
         return out
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok,
+                              valid_values=self.valid_values,
+                              length=self.length)
+
 
 class Bool(BaseType):
 
@@ -772,6 +799,10 @@ def to_str(self, value: typing.Union[None, int, float]) -> str:
             return ''
         return str(value)
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok, minval=self.minval,
+                              maxval=self.maxval)
+
 
 class Int(_Numeric):
 
@@ -924,6 +955,11 @@ def to_py(
             self._validate_bounds(value)
         return value
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok, minint=self.minval,
+                              maxint=self.maxval, minperc=self.minperc,
+                              maxperc=self.maxperc)
+
 
 class Command(BaseType):
 
@@ -1301,6 +1337,9 @@ def to_str(self,
             assert isinstance(value, str)
             return value
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok, flags=self.flags)
+
 
 class Dict(BaseType):
 
@@ -1403,6 +1442,11 @@ def to_doc(self, value: typing.Dict, indent: int = 0) -> str:
             )).splitlines()
         return '\n'.join(line.rstrip(' ') for line in lines)
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok, keytype=self.keytype,
+                              valtype=self.valtype, fixed_keys=self.fixed_keys,
+                              required_keys=self.required_keys)
+
 
 class File(BaseType):
 
@@ -1435,6 +1479,10 @@ def to_py(self, value: _StrUnset) -> _StrUnsetNone:
 
         return value
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok,
+                              required=self.required)
+
 
 class Directory(BaseType):
 
@@ -1487,6 +1535,9 @@ def to_py(self, value: _StrUnset) -> _StrUnsetNone:
 
         return value
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok, fields=self.fields)
+
 
 class ShellCommand(List):
 
@@ -1523,6 +1574,10 @@ def to_py(
                                             "{file}-placeholder.")
         return py_value
 
+    def __repr__(self):
+        return utils.get_repr(self, none_ok=self.none_ok,
+                              placeholder=self.placeholder)
+
 
 class Proxy(BaseType):
 


Test patch: