You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bazarr/libs/dynaconf/vendor/tomllib/_writer.py

89 lines
3.5 KiB

from __future__ import annotations
_C=True
_B=False
_A='\n'
from collections.abc import Generator,Mapping
from datetime import date,datetime,time
from decimal import Decimal
import string
from types import MappingProxyType
from typing import Any,BinaryIO,NamedTuple
ASCII_CTRL=frozenset(chr(A)for A in range(32))|frozenset(chr(127))
ILLEGAL_BASIC_STR_CHARS=frozenset('"\\')|ASCII_CTRL-frozenset('\t')
BARE_KEY_CHARS=frozenset(string.ascii_letters+string.digits+'-_')
ARRAY_TYPES=list,tuple
ARRAY_INDENT=' '*4
MAX_LINE_LENGTH=100
COMPACT_ESCAPES=MappingProxyType({'\x08':'\\b',_A:'\\n','\x0c':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'})
def dump(__obj,__fp,*,multiline_strings=_B):
A=Context(multiline_strings,{})
for B in gen_table_chunks(__obj,A,name=''):__fp.write(B.encode())
def dumps(__obj,*,multiline_strings=_B):A=Context(multiline_strings,{});return''.join(gen_table_chunks(__obj,A,name=''))
class Context(NamedTuple):allow_multiline:bool;inline_table_cache:dict[int,str]
def gen_table_chunks(table,ctx,*,name,inside_aot=_B):
H=inside_aot;G=ctx;C=name;D=_B;E=[];F=[]
for(B,A)in table.items():
if isinstance(A,dict):F.append((B,A,_B))
elif is_aot(A)and not all(is_suitable_inline_table(A,G)for A in A):F.extend((B,A,_C)for A in A)
else:E.append((B,A))
if H or C and(E or not F):D=_C;yield f"[[{C}]]\n"if H else f"[{C}]\n"
if E:
D=_C
for(B,A)in E:yield f"{format_key_part(B)} = {format_literal(A,G)}\n"
for(B,A,J)in F:
if D:yield _A
else:D=_C
I=format_key_part(B);K=f"{C}.{I}"if C else I;yield from gen_table_chunks(A,G,name=K,inside_aot=J)
def format_literal(obj,ctx,*,nest_level=0):
B=ctx;A=obj
if isinstance(A,bool):return'true'if A else'false'
if isinstance(A,(int,float,date,datetime)):return str(A)
if isinstance(A,Decimal):return format_decimal(A)
if isinstance(A,time):
if A.tzinfo:raise ValueError('TOML does not support offset times')
return str(A)
if isinstance(A,str):return format_string(A,allow_multiline=B.allow_multiline)
if isinstance(A,ARRAY_TYPES):return format_inline_array(A,B,nest_level)
if isinstance(A,dict):return format_inline_table(A,B)
raise TypeError(f"Object of type {type(A)} is not TOML serializable")
def format_decimal(obj):
C='-inf';B='inf';A=obj
if A.is_nan():return'nan'
if A==Decimal(B):return B
if A==Decimal(C):return C
return str(A)
def format_inline_table(obj,ctx):
B=obj;A=ctx;C=id(B)
if C in A.inline_table_cache:return A.inline_table_cache[C]
if not B:D='{}'
else:D='{ '+', '.join(f"{format_key_part(B)} = {format_literal(C,A)}"for(B,C)in B.items())+' }'
A.inline_table_cache[C]=D;return D
def format_inline_array(obj,ctx,nest_level):
A=nest_level
if not obj:return'[]'
B=ARRAY_INDENT*(1+A);C=ARRAY_INDENT*A;return'[\n'+',\n'.join(B+format_literal(C,ctx,nest_level=A+1)for C in obj)+f",\n{C}]"
def format_key_part(part):
A=part
if A and BARE_KEY_CHARS.issuperset(A):return A
return format_string(A,allow_multiline=_B)
def format_string(s,*,allow_multiline):
D=allow_multiline and _A in s
if D:A='"""\n';s=s.replace('\r\n',_A)
else:A='"'
B=E=0
while _C:
try:C=s[B]
except IndexError:
A+=s[E:B]
if D:return A+'"""'
return A+'"'
if C in ILLEGAL_BASIC_STR_CHARS:
A+=s[E:B]
if C in COMPACT_ESCAPES:
if D and C==_A:A+=_A
else:A+=COMPACT_ESCAPES[C]
else:A+='\\u'+hex(ord(C))[2:].rjust(4,'0')
E=B+1
B+=1
def is_aot(obj):A=obj;return bool(isinstance(A,ARRAY_TYPES)and A and all(isinstance(A,dict)for A in A))
def is_suitable_inline_table(obj,ctx):A=f"{ARRAY_INDENT}{format_inline_table(obj,ctx)},";return len(A)<=MAX_LINE_LENGTH and _A not in A