128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2024-2025 Mike Fährmann
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
# published by the Free Software Foundation.
|
|
|
|
import re
|
|
|
|
|
|
def pyprint(obj, indent=0, sort=None, oneline=True, lmin=0, lmax=16):
|
|
|
|
if isinstance(obj, str):
|
|
if obj.startswith("lit:"):
|
|
return f'''{obj[4:]}'''
|
|
|
|
if "\\" in obj or obj.startswith("re:"):
|
|
prefix = "r"
|
|
else:
|
|
prefix = ""
|
|
|
|
if "\n" in obj:
|
|
quote = '"""'
|
|
elif '"' in obj:
|
|
obj = re.sub(r'(?<!\\)"', '\\"', obj)
|
|
quote = '"'
|
|
else:
|
|
quote = '"'
|
|
|
|
return f'''{prefix}{quote}{obj}{quote}'''
|
|
|
|
if isinstance(obj, bytes):
|
|
return f'''b"{str(obj)[2:-1]}"'''
|
|
|
|
if isinstance(obj, type):
|
|
if obj.__module__ == "builtins":
|
|
return f'''{obj.__name__}'''
|
|
|
|
name = obj.__module__.rpartition(".")[2]
|
|
if name[0].isdecimal():
|
|
name = f"_{name}"
|
|
return f'''{name}.{obj.__name__}'''
|
|
|
|
if isinstance(obj, dict):
|
|
if not obj:
|
|
return "{}"
|
|
if len(obj) == 1 and oneline:
|
|
key, value = next(iter(obj.items()))
|
|
return f'''{{"{key}": {pyprint(value, indent, sort)}}}'''
|
|
|
|
if sort:
|
|
if callable(sort):
|
|
lst = [(sort(key, value), key, value)
|
|
for key, value in obj.items()]
|
|
lst.sort()
|
|
obj = {key: value for _, key, value in lst}
|
|
else:
|
|
keys = list(obj)
|
|
keys.sort()
|
|
obj = {key: obj[key] for key in keys}
|
|
|
|
try:
|
|
keylen = max(kl for kl in map(len, obj) if kl <= lmax)
|
|
except Exception:
|
|
keylen = lmin
|
|
if keylen < lmin:
|
|
keylen = lmin
|
|
ws = " " * indent
|
|
|
|
lines = ["{"]
|
|
for key, value in obj.items():
|
|
if key.startswith("#blank-"):
|
|
lines.append("")
|
|
else:
|
|
lines.append(
|
|
f'''{ws} "{key}"'''
|
|
f'''{' '*(keylen - len(key))}: '''
|
|
f'''{pyprint(value, indent+4, sort)},'''
|
|
)
|
|
lines.append(f'''{ws}}}''')
|
|
return "\n".join(lines)
|
|
|
|
if isinstance(obj, list):
|
|
if not obj:
|
|
return "[]"
|
|
if len(obj) == 1 and oneline:
|
|
return f'''[{pyprint(obj[0], indent, sort)}]'''
|
|
|
|
ws = " " * indent
|
|
lines = ["["]
|
|
for value in obj:
|
|
lines.append(f'''{ws} {pyprint(value, indent+4, sort)},''')
|
|
lines.append(f'''{ws}]''')
|
|
return "\n".join(lines)
|
|
|
|
if isinstance(obj, tuple):
|
|
if not obj:
|
|
return "()"
|
|
if len(obj) == 1:
|
|
return f'''({pyprint(obj[0], indent, sort)},)'''
|
|
|
|
result = f'''({", ".join(pyprint(v, indent+4, sort) for v in obj)})'''
|
|
if len(result) < 80:
|
|
return result
|
|
|
|
ws = " " * indent
|
|
lines = ["("]
|
|
for value in obj:
|
|
lines.append(f'''{ws} {pyprint(value, indent+4, sort)},''')
|
|
lines.append(f'''{ws})''')
|
|
return "\n".join(lines)
|
|
|
|
if isinstance(obj, set):
|
|
if not obj:
|
|
return "set()"
|
|
return f'''{{{", ".join(pyprint(v, indent+4, sort) for v in obj)}}}'''
|
|
|
|
if obj.__class__.__name__ == "datetime":
|
|
if (off := obj.utcoffset()) is not None:
|
|
obj = obj.replace(tzinfo=None, microsecond=0) - off
|
|
elif obj.microsecond:
|
|
obj = obj.replace(microsecond=0)
|
|
return f'''"dt:{obj}"'''
|
|
|
|
return f'''{obj}'''
|