| |
| """ |
| Part of the astor library for Python AST manipulation. |
| |
| License: 3-clause BSD |
| |
| Copyright (c) 2015 Patrick Maupin |
| |
| Pretty-print strings for the decompiler |
| |
| We either return the repr() of the string, |
| or try to format it as a triple-quoted string. |
| |
| This is a lot harder than you would think. |
| |
| This has lots of Python 2 / Python 3 ugliness. |
| |
| """ |
|
|
| import re |
|
|
| try: |
| special_unicode = unicode |
| except NameError: |
| class special_unicode(object): |
| pass |
|
|
| try: |
| basestring = basestring |
| except NameError: |
| basestring = str |
|
|
|
|
| def _properly_indented(s, line_indent): |
| mylist = s.split('\n')[1:] |
| mylist = [x.rstrip() for x in mylist] |
| mylist = [x for x in mylist if x] |
| if not s: |
| return False |
| counts = [(len(x) - len(x.lstrip())) for x in mylist] |
| return counts and min(counts) >= line_indent |
|
|
|
|
| mysplit = re.compile(r'(\\|\"\"\"|\"$)').split |
| replacements = {'\\': '\\\\', '"""': '""\\"', '"': '\\"'} |
|
|
|
|
| def _prep_triple_quotes(s, mysplit=mysplit, replacements=replacements): |
| """ Split the string up and force-feed some replacements |
| to make sure it will round-trip OK |
| """ |
|
|
| s = mysplit(s) |
| s[1::2] = (replacements[x] for x in s[1::2]) |
| return ''.join(s) |
|
|
|
|
| def string_triplequote_repr(s): |
| """Return string's python representation in triple quotes. |
| """ |
| return '"""%s"""' % _prep_triple_quotes(s) |
|
|
|
|
| def pretty_string(s, embedded, current_line, uni_lit=False, |
| min_trip_str=20, max_line=100): |
| """There are a lot of reasons why we might not want to or |
| be able to return a triple-quoted string. We can always |
| punt back to the default normal string. |
| """ |
|
|
| default = repr(s) |
|
|
| |
| if (isinstance(s, special_unicode) or not isinstance(s, basestring)): |
| return default |
| if uni_lit and isinstance(s, bytes): |
| return 'b' + default |
|
|
| len_s = len(default) |
|
|
| if current_line.strip(): |
| len_current = len(current_line) |
| second_line_start = s.find('\n') + 1 |
| if embedded > 1 and not second_line_start: |
| return default |
|
|
| if len_s < min_trip_str: |
| return default |
|
|
| line_indent = len_current - len(current_line.lstrip()) |
|
|
| |
| if embedded and not second_line_start: |
| return default |
|
|
| total_len = len_current + len_s |
| if total_len < max_line and not _properly_indented(s, line_indent): |
| return default |
|
|
| fancy = string_triplequote_repr(s) |
|
|
| |
| |
| |
| |
|
|
| try: |
| if eval(fancy) == s and '\r' not in fancy: |
| return fancy |
| except Exception: |
| pass |
| return default |
|
|