Compare commits

..

No commits in common. "fccb22aed54a7afd3000886309cea1dd1b82be2f" and "b6db88516793004a0d47bc6948a66ee90be0d9db" have entirely different histories.

2 changed files with 32 additions and 36 deletions

View File

@ -2,7 +2,6 @@
from __future__ import annotations
import datetime
import json
import re
@ -17,7 +16,7 @@ _SUBTABLE = rf'(?P<subtable>^\[(?P<is_list>\[)?(?P<path>{KEY_RE.pattern})\]\]?)'
EXPRESSION_RE = re.compile(rf'^(?:{_SUBTABLE}|{KEY_RE.pattern}=)', re.MULTILINE)
LIST_WS_RE = re.compile(rf'{WS}((#[^\n]*)?\n{WS})*')
LEFTOVER_VALUE_RE = re.compile(r'[^,}\]\t\n#]+')
UNKNOWN_VALUE_RE = re.compile(r'[^,}\] \t\n#]+')
def parse_key(value: str):
@ -37,16 +36,22 @@ def get_target(root: dict, paths: list[str], is_list=False):
use_list = is_list and index == len(paths)
result = target.get(key)
if result is None:
result = [] if use_list else {}
target[key] = result
if use_list:
target[key] = _temp = []
target = {}
_temp.append(target)
else:
target[key] = target = {}
elif isinstance(result, list):
if use_list:
target = {}
result.append(target)
else:
target = result[-1]
if isinstance(result, dict):
target = result
elif use_list:
target = {}
result.append(target)
else:
target = result[-1]
target = result
assert isinstance(target, dict)
return target
@ -55,8 +60,9 @@ def get_target(root: dict, paths: list[str], is_list=False):
def parse_enclosed(data: str, index: int, end: str, ws_re: re.Pattern):
index += 1
if match := ws_re.match(data, index):
index = match.end()
match = ws_re.match(data, index)
assert match
index = match.end()
while data[index] != end:
index = yield True, index
@ -67,10 +73,10 @@ def parse_enclosed(data: str, index: int, end: str, ws_re: re.Pattern):
if data[index] == ',':
index += 1
if match := ws_re.match(data, index):
index = match.end()
match = ws_re.match(data, index)
assert match
index = match.end()
assert data[index] == end
yield False, index + 1
@ -100,22 +106,15 @@ def parse_value(data: str, index: int):
if match := STRING_RE.match(data, index):
return match.end(), json.loads(match[0]) if match[0][0] == '"' else match[0][1:-1]
match = LEFTOVER_VALUE_RE.match(data, index)
# bool, int, float or date. Of these, only bool is used in pyproject.toml, so ignore others
match = UNKNOWN_VALUE_RE.match(data, index)
assert match
value = match[0].strip()
for func in [
int,
float,
datetime.time.fromisoformat,
datetime.date.fromisoformat,
datetime.datetime.fromisoformat,
{'true': True, 'false': False}.get,
]:
try:
value = func(value)
break
except Exception:
pass
if match[0] == 'true':
value = True
elif match[0] == 'false':
value = False
else:
value = None
return match.end(), value
@ -160,6 +159,7 @@ def parse_toml(data: str):
def main():
import argparse
import json
from pathlib import Path
parser = argparse.ArgumentParser()
@ -169,11 +169,7 @@ def main():
with args.infile.open('r', encoding='utf-8') as file:
data = file.read()
def default(obj):
if isinstance(obj, (datetime.date, datetime.time, datetime.datetime)):
return obj.isoformat()
print(json.dumps(parse_toml(data), default=default))
print(json.dumps(parse_toml(data)))
if __name__ == '__main__':

View File

@ -35,7 +35,7 @@ classifiers = [
"Programming Language :: Python :: Implementation",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"License :: OSI Approved :: The Unlicense (Unlicense)",
"License :: Public Domain",
"Operating System :: OS Independent",
]
dynamic = ["version"]