ckparser 0.2.1__tar.gz → 0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ckparser-0.2.1/ckparser.egg-info → ckparser-0.3}/PKG-INFO +1 -1
- {ckparser-0.2.1 → ckparser-0.3/ckparser.egg-info}/PKG-INFO +1 -1
- {ckparser-0.2.1 → ckparser-0.3}/ckparser.py +39 -31
- {ckparser-0.2.1 → ckparser-0.3}/pyproject.toml +1 -1
- {ckparser-0.2.1 → ckparser-0.3}/LICENSE +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/MANIFEST.in +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/README.md +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/ckparser.egg-info/SOURCES.txt +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/ckparser.egg-info/dependency_links.txt +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/ckparser.egg-info/entry_points.txt +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/ckparser.egg-info/requires.txt +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/ckparser.egg-info/top_level.txt +0 -0
- {ckparser-0.2.1 → ckparser-0.3}/setup.cfg +0 -0
|
@@ -41,7 +41,7 @@ import re
|
|
|
41
41
|
import time
|
|
42
42
|
|
|
43
43
|
# Script version
|
|
44
|
-
__version__ = "0.
|
|
44
|
+
__version__ = "0.3"
|
|
45
45
|
|
|
46
46
|
# Logger (because logging is awesome)
|
|
47
47
|
logger = logging.getLogger(__name__)
|
|
@@ -82,8 +82,8 @@ def jomini_object_hook(obj):
|
|
|
82
82
|
|
|
83
83
|
json_load = functools.partial(json.load, object_hook=jomini_object_hook)
|
|
84
84
|
json_loads = functools.partial(json.loads, object_hook=jomini_object_hook)
|
|
85
|
-
json_dump = functools.partial(json.dump, cls=JominiJSONEncoder, indent=4
|
|
86
|
-
json_dumps = functools.partial(json.dumps, cls=JominiJSONEncoder, indent=4
|
|
85
|
+
json_dump = functools.partial(json.dump, cls=JominiJSONEncoder, indent=4)
|
|
86
|
+
json_dumps = functools.partial(json.dumps, cls=JominiJSONEncoder, indent=4)
|
|
87
87
|
|
|
88
88
|
# Boolean transformation
|
|
89
89
|
booleans = {"yes": True, "no": False}
|
|
@@ -102,7 +102,7 @@ regex_string_multiline = re.compile(r"\"[^\"]*\"", re.MULTILINE)
|
|
|
102
102
|
# Regex for quoted strings inside quoted strings
|
|
103
103
|
regex_inner_string = re.compile(r"\|(?P<index>\d+)\|")
|
|
104
104
|
# Regex to remove comments in files
|
|
105
|
-
regex_comment = re.compile(r"(?P<space>\s*)(?P<comment>#.*)
|
|
105
|
+
regex_comment = re.compile(r"(?P<space>\s*)(?P<comment>#.*)")
|
|
106
106
|
# Regex to fix blocks with no equal sign
|
|
107
107
|
regex_block = re.compile(r"^([^\s\{\=]+)\s*\{\s*$", re.MULTILINE)
|
|
108
108
|
# Regex to remove "list" prefix
|
|
@@ -111,8 +111,8 @@ regex_list = re.compile(r"\s*=\s*list\s+([\{\"\|])", re.MULTILINE)
|
|
|
111
111
|
regex_color = re.compile(r"=\s*(?P<type>\w+)\s*{")
|
|
112
112
|
# Regex to parse items with format key=value
|
|
113
113
|
regex_inline = re.compile(r"([^\s\"]+\s*[?!<=>]+\s*(([^@\"]\[?[^\s]+\]?)|(\"[^\"]+\")|(@\[[^\]]+\]))|(@\w+))")
|
|
114
|
-
# Regex to parse blocks with bracket below the key
|
|
115
|
-
regex_values = re.compile(r"(([?!<=>]+)\s
|
|
114
|
+
# Regex to parse blocks with bracket below the key/operator
|
|
115
|
+
regex_values = re.compile(r"(\s*([?!<=>]+)\s+\{)|(\s+\s*([?!<=>])+\s*\{)")
|
|
116
116
|
# Regex to parse lines with format key=value
|
|
117
117
|
regex_line = re.compile(r"\"?(?P<key>[^\s\"]+)\"?\s*(?P<operator>[?!<=>]+)\s*(list\s*)?(?P<value>.*)")
|
|
118
118
|
# Regex to parse independent items in a list
|
|
@@ -125,6 +125,8 @@ regex_empty = re.compile(r"(\n\s*\n)+", re.MULTILINE)
|
|
|
125
125
|
regex_locale = re.compile(r"^\s*(?P<key>[^\:#]+)\:(\d+)?\s\"(?P<value>.+)\".*$")
|
|
126
126
|
# Regex for keywords
|
|
127
127
|
regex_keyword = re.compile(r"(" + "|".join(map(re.escape, sorted(keywords, key=len, reverse=True))) + r") ")
|
|
128
|
+
# Regex for fixing line count when bracket is below the key/operator
|
|
129
|
+
regex_count = re.compile(r"([?!<=>]+)\s*§\n+\s*\{")
|
|
128
130
|
# Regex for string indexes
|
|
129
131
|
regex_index = re.compile(r"\|(\d+)\|")
|
|
130
132
|
# Regex for variables
|
|
@@ -182,7 +184,7 @@ def read_file(path, encoding="utf_8_sig"):
|
|
|
182
184
|
encoding = result["encoding"]
|
|
183
185
|
logger.debug(f"Detected encoding: {result['encoding']} ({result['confidence']:0.0%})")
|
|
184
186
|
del raw_data
|
|
185
|
-
with open(path, encoding=encoding) as file:
|
|
187
|
+
with open(path, "r", encoding=encoding) as file:
|
|
186
188
|
return file.read()
|
|
187
189
|
|
|
188
190
|
|
|
@@ -199,19 +201,19 @@ def parse_text(text, return_text_on_error=False, comments=False, dates=False, fi
|
|
|
199
201
|
"""
|
|
200
202
|
|
|
201
203
|
def replace(match):
|
|
202
|
-
nonlocal strings,
|
|
203
|
-
|
|
204
|
-
strings[str(
|
|
205
|
-
return f"|{
|
|
204
|
+
nonlocal strings, strings_index
|
|
205
|
+
strings_index = len(strings)
|
|
206
|
+
strings[str(strings_index)] = match.group(0).replace("\n", "\\n")
|
|
207
|
+
return f"|{strings_index}|"
|
|
206
208
|
|
|
207
209
|
def replace_comment(match):
|
|
208
|
-
nonlocal strings,
|
|
209
|
-
|
|
210
|
+
nonlocal strings, strings_index
|
|
211
|
+
strings_index = len(strings)
|
|
210
212
|
value, space = match.group("comment").replace('"', "'").strip(), match.group("space")
|
|
211
|
-
strings[str(
|
|
213
|
+
strings[str(strings_index)] = f'"{value}"'
|
|
212
214
|
if not value.strip():
|
|
213
215
|
return ""
|
|
214
|
-
return f"\n{space}#{
|
|
216
|
+
return f"\n{space}#{strings_index}=|{strings_index}|"
|
|
215
217
|
|
|
216
218
|
def set_variable(key, value, is_global=is_global):
|
|
217
219
|
global global_variables
|
|
@@ -223,29 +225,35 @@ def parse_text(text, return_text_on_error=False, comments=False, dates=False, fi
|
|
|
223
225
|
|
|
224
226
|
root = {}
|
|
225
227
|
nodes = [("", root)]
|
|
226
|
-
strings,
|
|
228
|
+
strings, strings_index = {}, 0
|
|
227
229
|
variables = global_variables.copy()
|
|
228
230
|
# Cleaning document
|
|
231
|
+
text = text.replace("\n", "\n§\n")
|
|
229
232
|
text = regex_string.sub(replace, text)
|
|
230
233
|
if comments:
|
|
231
234
|
text = regex_comment.sub(replace_comment, text)
|
|
232
235
|
else:
|
|
233
236
|
text = regex_comment.sub("", text)
|
|
237
|
+
text = text.replace("{", "\n{\n").replace("}", "\n}\n")
|
|
234
238
|
text = regex_string_multiline.sub(replace, text)
|
|
235
239
|
text = regex_list.sub(r"|list=\g<1>", text)
|
|
236
|
-
text = regex_block.sub(r"\g<1>={", text)
|
|
237
|
-
text = text.replace("{", "\n{\n").replace("}", "\n}\n")
|
|
238
240
|
text = regex_color.sub(r"={\n\g<1>", text)
|
|
239
241
|
text = regex_inline.sub(r"\g<1>\n", text)
|
|
240
|
-
text = regex_values.sub(r"\g<2>\g<4>", text)
|
|
242
|
+
text = regex_values.sub(r"\g<2>\g<4>{", text)
|
|
241
243
|
text = regex_empty.sub(r"\n", text)
|
|
242
244
|
text = regex_keyword.sub(r"\1|", text)
|
|
245
|
+
text = regex_count.sub(r"\g<1>{\n§", text)
|
|
243
246
|
text = regex_index.sub(lambda match: strings[match.group(1)], text)
|
|
244
247
|
|
|
245
248
|
# Parsing document line by line
|
|
246
|
-
|
|
249
|
+
line_number = 1
|
|
250
|
+
for line_text in text.splitlines():
|
|
247
251
|
try:
|
|
248
252
|
line_text = line_text.strip()
|
|
253
|
+
# Line number
|
|
254
|
+
if count := line_text.count("§"):
|
|
255
|
+
line_number += count
|
|
256
|
+
line_text = line_text.rstrip("§")
|
|
249
257
|
# Nothing to do if line is empty
|
|
250
258
|
if not line_text:
|
|
251
259
|
continue
|
|
@@ -511,32 +519,32 @@ def parse_file(
|
|
|
511
519
|
start_time = time.monotonic()
|
|
512
520
|
if base_dir:
|
|
513
521
|
base_dir = os.sep.join(str(base_dir).rstrip(os.sep).split(os.sep)[:-1]) + os.sep
|
|
514
|
-
base_dir = os.path.dirname(path.replace(base_dir
|
|
522
|
+
base_dir = os.path.dirname(path.replace(base_dir, ""))
|
|
515
523
|
base_dir = base_dir or "."
|
|
516
524
|
text = read_file(path, encoding)
|
|
517
525
|
if not text or not text.strip():
|
|
518
526
|
return None
|
|
519
527
|
for pattern, replacement in patch or []:
|
|
520
528
|
text = re.sub(pattern, replacement, text)
|
|
521
|
-
filename = os.path.join(base_dir, os.path.basename(path))
|
|
529
|
+
filename = os.path.join(base_dir, os.path.basename(path))
|
|
522
530
|
logger.debug(f"Parsing {filename}")
|
|
523
531
|
data = parse_text(
|
|
524
532
|
text, return_text_on_error=True, comments=comments, dates=dates, filename=filename, is_global=is_global
|
|
525
533
|
)
|
|
526
534
|
if save:
|
|
527
535
|
filename, _ = os.path.splitext(os.path.basename(path))
|
|
528
|
-
directory = os.path.join(output_dir or "output", *base_dir.split(
|
|
536
|
+
directory = os.path.join(output_dir or "output", *base_dir.split(os.sep))
|
|
529
537
|
os.makedirs(directory, exist_ok=True)
|
|
530
538
|
if not isinstance(data, dict):
|
|
531
539
|
filename = os.path.join(directory, filename + ".error")
|
|
532
540
|
try:
|
|
533
|
-
with open(filename, "w") as file:
|
|
541
|
+
with open(filename, "w", encoding=encoding) as file:
|
|
534
542
|
file.write(data)
|
|
535
543
|
except UnicodeEncodeError as error:
|
|
536
544
|
logger.error(f"Unable to write file {filename}: {error}")
|
|
537
545
|
else:
|
|
538
546
|
filename = os.path.join(directory, filename + ".json")
|
|
539
|
-
with open(filename, "w") as file:
|
|
547
|
+
with open(filename, "w", encoding="utf-8") as file:
|
|
540
548
|
json_dump(data, file)
|
|
541
549
|
total_time = time.monotonic() - start_time
|
|
542
550
|
logger.debug(f"Elapsed time: {total_time:0.3f}s!")
|
|
@@ -589,7 +597,7 @@ def parse_all_files(
|
|
|
589
597
|
for filename in all_files:
|
|
590
598
|
if not filename.lower().endswith(".txt"):
|
|
591
599
|
continue
|
|
592
|
-
filepath = os.path.join(current_path, filename)
|
|
600
|
+
filepath = os.path.join(current_path, filename)
|
|
593
601
|
data = parse_file(
|
|
594
602
|
filepath,
|
|
595
603
|
output_dir=output_dir,
|
|
@@ -603,7 +611,7 @@ def parse_all_files(
|
|
|
603
611
|
if isinstance(data, str):
|
|
604
612
|
errors.append(filepath)
|
|
605
613
|
continue
|
|
606
|
-
filepath = filepath.replace(str(path), "").lstrip(
|
|
614
|
+
filepath = filepath.replace(str(path), "").lstrip(os.sep)
|
|
607
615
|
success[filepath] = data if keep_data else True
|
|
608
616
|
total_time = time.monotonic() - start_time
|
|
609
617
|
logger.info(f"{len(success)} parsed file(s) and {len(errors)} errors in {total_time:0.3f}s!")
|
|
@@ -647,7 +655,7 @@ def parse_all_locales(path, encoding="utf_8_sig", language="english", save=False
|
|
|
647
655
|
key, _, value = match.groups()
|
|
648
656
|
locales[key] = value
|
|
649
657
|
if save:
|
|
650
|
-
with open(output, "w") as file:
|
|
658
|
+
with open(output, "w", encoding="utf-8") as file:
|
|
651
659
|
json_dump(locales, file, sort_keys=True)
|
|
652
660
|
return locales
|
|
653
661
|
|
|
@@ -822,7 +830,7 @@ def revert_file(path, output_dir=None, encoding="utf_8_sig", base_dir=None, save
|
|
|
822
830
|
base_dir = os.sep.join(str(base_dir).rstrip(os.sep).split(os.sep)[:-1]) + os.sep
|
|
823
831
|
base_dir = os.path.dirname(path.replace(base_dir, ""))
|
|
824
832
|
base_dir = base_dir or "."
|
|
825
|
-
with open(path) as file:
|
|
833
|
+
with open(path, "r", encoding="utf-8") as file:
|
|
826
834
|
data = json.load(file)
|
|
827
835
|
filename = os.path.join(str(base_dir), os.path.basename(path))
|
|
828
836
|
logger.debug(f"Reverting {filename}")
|
|
@@ -846,7 +854,7 @@ def load_variables(filepath="_variables.json"):
|
|
|
846
854
|
global global_variables
|
|
847
855
|
if not os.path.exists(filepath):
|
|
848
856
|
return
|
|
849
|
-
with open(filepath) as file:
|
|
857
|
+
with open(filepath, "r", encoding="utf-8") as file:
|
|
850
858
|
global_variables = json.load(file)
|
|
851
859
|
|
|
852
860
|
|
|
@@ -856,7 +864,7 @@ def save_variables(filepath="_variables.json"):
|
|
|
856
864
|
"""
|
|
857
865
|
if not global_variables:
|
|
858
866
|
return
|
|
859
|
-
with open(filepath, "w") as file:
|
|
867
|
+
with open(filepath, "w", encoding="utf-8") as file:
|
|
860
868
|
json_dump(global_variables, file, sort_keys=True)
|
|
861
869
|
|
|
862
870
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|