From: Henryk Plötz Date: Tue, 14 Aug 2018 17:16:01 +0000 (+0200) Subject: Add a bad hack to RepresentableEnum to get docstrings on enum members. Make the docum... X-Git-Tag: v2.0.0~1^2~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4b081927f9efa7096a1fe229bd9066fc174bf81a;p=thirdparty%2Fpython-fints.git Add a bad hack to RepresentableEnum to get docstrings on enum members. Make the documented output better --- diff --git a/fints/fields.py b/fints/fields.py index dac8442..6232708 100644 --- a/fints/fields.py +++ b/fints/fields.py @@ -85,6 +85,13 @@ class Field: return self._render_value(value) + def _inline_doc_comment(self, value): + if self.__doc__: + d = self.__doc__.splitlines()[0].strip() + if d: + return " # {}".format(d) + return "" + class TypedField(Field, SubclassesMixin): flat_length = 1 @@ -257,6 +264,18 @@ class CodeField(AlphanumericField): retval = str(value.value) return super()._render_value(retval) + def _inline_doc_comment(self, value): + retval = super()._inline_doc_comment(value) + if self._enum: + addendum = value.__doc__ + if addendum and not addendum is value.__class__.__doc__: + if not retval: + retval = " # " + else: + retval = retval + ": " + retval = retval + addendum + return retval + class CountryField(FixedLengthMixin, DigitsField): type = 'ctr' _FIXED_LENGTH = [3] diff --git a/fints/formals.py b/fints/formals.py index 65b0929..4f88bff 100644 --- a/fints/formals.py +++ b/fints/formals.py @@ -300,9 +300,9 @@ class AccountInternational(DataElementGroup): bank_identifier = DataElementGroupField(type=BankIdentifier) class SecurityRole(RepresentableEnum): - ISS = '1' - CON = '3' - WIT = '4' + ISS = '1' #: Erfasser, Erstsignatur + CON = '3' #: Unterstützer, Zweitsignatur + WIT = '4' #: Zeuge/Übermittler, nicht Erfasser class CompressionFunction(RepresentableEnum): NULL = '0' #: Keine Kompression diff --git a/fints/types.py b/fints/types.py index e2c07d5..5174aef 100644 --- a/fints/types.py +++ b/fints/types.py @@ -67,13 +67,13 @@ class ValueList: def __repr__(self): return "{!r}".format(list(self)) - def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer=""): + def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer="", print_doc=True, first_line_suffix=""): import sys stream = stream or sys.stdout stream.write( ( (prefix + level*indent) if first_level_indent else "") - + "[\n" + + "[{}\n".format(first_line_suffix) ) for val in self: if not hasattr( getattr(val, 'print_nested', None), '__call__'): @@ -81,7 +81,7 @@ class ValueList: (prefix + (level+1)*indent) + "{!r},\n".format(val) ) else: - val.print_nested(stream=stream, level=level+2, indent=indent, prefix=prefix, trailer=",") + val.print_nested(stream=stream, level=level+2, indent=indent, prefix=prefix, trailer=",", print_doc=print_doc) stream.write( (prefix + level*indent) + "]{}\n".format(trailer) ) class SegmentSequence: @@ -102,15 +102,17 @@ class SegmentSequence: def __repr__(self): return "{}.{}({!r})".format(self.__class__.__module__, self.__class__.__name__, self.segments) - def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer=""): + def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer="", print_doc=True, first_line_suffix=""): import sys stream = stream or sys.stdout stream.write( ( (prefix + level*indent) if first_level_indent else "") - + "{}.{}([".format(self.__class__.__module__, self.__class__.__name__) + "\n" + + "{}.{}([".format(self.__class__.__module__, self.__class__.__name__) + + first_line_suffix + + "\n" ) for segment in self.segments: - segment.print_nested(stream=stream, level=level+1, indent=indent, prefix=prefix, first_level_indent=True, trailer=",") + segment.print_nested(stream=stream, level=level+1, indent=indent, prefix=prefix, first_level_indent=True, trailer=",", print_doc=print_doc) stream.write( (prefix + level*indent) + "]){}\n".format(trailer) ) def find_segments(self, query=None, version=None, callback=None, recurse=True): @@ -243,7 +245,7 @@ class Container(metaclass=ContainerMeta): ) ) - def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer=""): + def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer="", print_doc=True, first_line_suffix=""): """Structured nested print of the object to the given stream. The print-out is eval()able to reconstruct the object.""" @@ -252,17 +254,23 @@ class Container(metaclass=ContainerMeta): stream.write( ( (prefix + level*indent) if first_level_indent else "") - + "{}.{}(".format(self.__class__.__module__, self.__class__.__name__) + "\n" + + "{}.{}(".format(self.__class__.__module__, self.__class__.__name__) + + first_line_suffix + + "\n" ) for name, value in self._repr_items: val = getattr(self, name) + if print_doc: + docstring = self._fields[name]._inline_doc_comment(val) + else: + docstring = "" if not hasattr( getattr(val, 'print_nested', None), '__call__'): stream.write( - (prefix + (level+1)*indent) + "{} = {!r},\n".format(name, val) + (prefix + (level+1)*indent) + "{} = {!r},{}\n".format(name, val, docstring) ) else: stream.write( (prefix + (level+1)*indent) + "{} = ".format(name) ) - val.print_nested(stream=stream, level=level+2, indent=indent, prefix=prefix, first_level_indent=False, trailer=",") + val.print_nested(stream=stream, level=level+2, indent=indent, prefix=prefix, first_level_indent=False, trailer=",", print_doc=print_doc, first_line_suffix=docstring) stream.write( (prefix + level*indent) + "){}\n".format(trailer) ) diff --git a/fints/utils.py b/fints/utils.py index 440f8cd..f92faad 100644 --- a/fints/utils.py +++ b/fints/utils.py @@ -1,3 +1,4 @@ +import inspect import re from contextlib import contextmanager from datetime import datetime @@ -118,10 +119,10 @@ class ShortReprMixin: ) ) - def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer=""): + def print_nested(self, stream=None, level=0, indent=" ", prefix="", first_level_indent=True, trailer="", print_doc=True, first_line_suffix=""): stream.write( ( (prefix + level*indent) if first_level_indent else "") - + "{!r}{}\n".format(self, trailer) + + "{!r}{}{}\n".format(self, trailer, first_line_suffix) ) @@ -250,9 +251,30 @@ class Password(str): return self.__str__().replace(*args, **kwargs) class RepresentableEnum(Enum): + def __init__(self, *args, **kwargs): + Enum.__init__(self) + + # Hack alert: Try to parse the docstring from the enum source, if available. Fail softly. + # FIXME Needs test + try: + val_1 = val_2 = repr(args[0]) + if val_1.startswith("'"): + val_2 = '"' + val_1[1:-1] + '"' + elif val_1.startswith('"'): + val_2 = "'" + val_1[1:-1] + "'" + regex = re.compile(r"^.*?\S+\s*=\s*(?:(?:{})|(?:{}))\s*#:\s*(\S.*)$".format( + re.escape(val_1), re.escape(val_2))) + for line in inspect.getsourcelines(self.__class__)[0]: + m = regex.match(line) + if m: + self.__doc__ = m.group(1).strip() + break + except: + raise + def __repr__(self): return "{}.{}.{}".format(self.__class__.__module__, self.__class__.__name__, self.name) def __str__(self): return self.value - +