|
|
@@ -2,97 +2,158 @@ import pathlib
|
|
|
import _io
|
|
|
|
|
|
from .pini_exception import pini_exception
|
|
|
+from .pini_exception import pini_syntax
|
|
|
from .pini import pini
|
|
|
from .key import key
|
|
|
from .section import section
|
|
|
|
|
|
-class parser:
|
|
|
- def __init__(self, target: str | _io.TextIOWrapper | pathlib.Path):
|
|
|
+class parser():
|
|
|
+ def __init__(self, target: str | pathlib.Path):
|
|
|
+ if target isinstance str:
|
|
|
+ target = pathlib.Path(target)
|
|
|
+
|
|
|
+ if not target.is_file():
|
|
|
+ raise pini_exception("File " + str(target) + " not exists.")
|
|
|
+
|
|
|
+ self.__current = None
|
|
|
+ self.__path = target
|
|
|
self.__config = pini()
|
|
|
- self.__section = section()
|
|
|
|
|
|
- if type(target) is str:
|
|
|
- target = pathlib.Path(target)
|
|
|
+ self.__process()
|
|
|
|
|
|
- if isinstance(target, pathlib.Path):
|
|
|
- if not target.is_file():
|
|
|
- raise pini_exception("File " + str(target) + "not exists.")
|
|
|
+ def __get_section(self) -> section:
|
|
|
+ if self.__current is None:
|
|
|
+ self.__current = section()
|
|
|
+ return self.__get_section()
|
|
|
|
|
|
- with target.open(mode = "r", encoding = "utf-8") as file:
|
|
|
- self.__read_file(file)
|
|
|
- return
|
|
|
+ return self.__current
|
|
|
|
|
|
- if type(target) is _io.TextIOWrapper:
|
|
|
- self.__read_file(file)
|
|
|
- return
|
|
|
+ def __new_section(self, name: str) -> section:
|
|
|
+ if type(name) is not str:
|
|
|
+ raise TypeError("New section name must be str.")
|
|
|
+
|
|
|
+ name = name.strip()
|
|
|
|
|
|
- raise TypeError("Target to parse must be str file, path, or file.")
|
|
|
+ if len(name) == 0:
|
|
|
+ raise pini_syntax("New section name can not be empty.")
|
|
|
|
|
|
- def __read_file(self, file: _io.TextIOWrapper) -> None:
|
|
|
- while True:
|
|
|
- line = file.readline()
|
|
|
-
|
|
|
- if len(line) == 0:
|
|
|
- break
|
|
|
+ if self.__current is not None:
|
|
|
+ self.__config.add(self.__current)
|
|
|
|
|
|
- self.__parse_line(line)
|
|
|
+ self.__current = section()
|
|
|
+ self.__current.name = name
|
|
|
+
|
|
|
+ def __process(self) -> None:
|
|
|
+ with self.__path.open() as file:
|
|
|
+ for line in file:
|
|
|
+ self.__parse_line(line)
|
|
|
|
|
|
def __parse_line(self, line: str) -> None:
|
|
|
line = line.lstrip()
|
|
|
|
|
|
- if line[0:3] == "###":
|
|
|
- self.__parse_key(line)
|
|
|
+ if len(line) == 0:
|
|
|
return
|
|
|
|
|
|
- if line[0] == "#":
|
|
|
- self.__parse_comment(line)
|
|
|
- return
|
|
|
+ first = line[0]
|
|
|
|
|
|
- if line[0] == "[":
|
|
|
+ if first == "[":
|
|
|
self.__parse_section(line)
|
|
|
return
|
|
|
-
|
|
|
- if line.find("="):
|
|
|
- self.__parse_key(line)
|
|
|
+
|
|
|
+ if first == "#":
|
|
|
+ if len(line) >= 3 and line[0:3] == "###":
|
|
|
+ self.__parse_unactive_key(line)
|
|
|
+ return
|
|
|
+
|
|
|
+ self.__parse_comment(line)
|
|
|
return
|
|
|
|
|
|
- def __parse_section(self, line: str) -> None:
|
|
|
- name_position = line.find("=")
|
|
|
- name = line[:name_position].strip()
|
|
|
- value = line[name_position + 1:].lstrip()
|
|
|
- value, comment = self.__parse_value(value)
|
|
|
-
|
|
|
- def __parse_value(self, value: str) -> [str | int | float, str | None]:
|
|
|
- if value[0] == "'" or value == "\"":
|
|
|
- return self.__parse_string(value)
|
|
|
-
|
|
|
- comment_split = value.split("#")
|
|
|
-
|
|
|
- if len(comment_split) == 1:
|
|
|
- pass
|
|
|
+ self.__parse_key(line)
|
|
|
|
|
|
- def __parse_string(self, value: str) -> [str | int | float, str | None]:
|
|
|
- tag = value[0]
|
|
|
- end = value.find(tag, 1)
|
|
|
- content = value[1:end]
|
|
|
+ def __split_comment(self, line: str) -> [str | None , str | None]:
|
|
|
+ position = line.find("#")
|
|
|
|
|
|
- comment = value[end + 1:].lstrip()
|
|
|
-
|
|
|
- if comment[0] != "#" and len(comment) > 0:
|
|
|
- raise pine_syntax("Chars after string close. " + comment)
|
|
|
+ if position == -1:
|
|
|
+ return line.strip(), None
|
|
|
|
|
|
- if len(comment) == 0:
|
|
|
- return content, None
|
|
|
+ content = line[:position].strip()
|
|
|
+ comment = line[position + 1:]
|
|
|
|
|
|
- if comment[0] == "#":
|
|
|
+ if len(comment) > 0 and comment[0] == " ":
|
|
|
comment = comment[1:]
|
|
|
|
|
|
- if comment[0] == " ":
|
|
|
- comment = comment[1:]
|
|
|
+ if len(content) == 0:
|
|
|
+ content = None
|
|
|
|
|
|
if len(comment) == 0:
|
|
|
comment = None
|
|
|
|
|
|
return content, comment
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+ def __parse_unactive_key(self, line: str) -> None:
|
|
|
+ line = line[3:]
|
|
|
+
|
|
|
+ if line[0] == " ":
|
|
|
+ line = line[1:]
|
|
|
+
|
|
|
+ content, comment = self.__split_comment(line)
|
|
|
+
|
|
|
+ if content is None:
|
|
|
+ if comment is None:
|
|
|
+ return
|
|
|
+
|
|
|
+ self.__get_section().add_comment(comment)
|
|
|
+
|
|
|
+ position = content.find("=")
|
|
|
+
|
|
|
+ target = key()
|
|
|
+ target.value = None
|
|
|
+ target.name = content.strip()
|
|
|
+ target.comment = comment
|
|
|
+
|
|
|
+ def __parse_key(self, line: str) -> None:
|
|
|
+ content, comment = self.__split_comment(line)
|
|
|
+
|
|
|
+ if content is None and comment is not None:
|
|
|
+ self.__parse_comment("#" + comment)
|
|
|
+ return
|
|
|
+
|
|
|
+ if content.count("=") != 1:
|
|
|
+ raise pini_syntax(""
|
|
|
+
|
|
|
+ def __parse_section(self, line: str) -> None:
|
|
|
+ content, comment = self.__split_comment(line)
|
|
|
+
|
|
|
+ if content.count("[") != 1 or content.count("]") != 1:
|
|
|
+ raise pini_syntax("Section name must start with [ and end with ].")
|
|
|
+
|
|
|
+ start = content.find("[") + 1
|
|
|
+ end = content.find("]")
|
|
|
+ name = content[start:end].strip()
|
|
|
+
|
|
|
+ if len(name) == 0:
|
|
|
+ raise pini_syntax("Section name can not be empty.")
|
|
|
+
|
|
|
+ if name.count(" ") > 0 or name.count("\t") > 0:
|
|
|
+ raise pini_syntax("Section name can not contain white chars.")
|
|
|
+
|
|
|
+ self.__new_section(name)
|
|
|
+
|
|
|
+ if comment is not None:
|
|
|
+ self.__get_section().add_comment(comment)
|
|
|
+
|
|
|
+ def __parse_comment(self, line: str) -> None:
|
|
|
+ if line[0] != "#":
|
|
|
+ return
|
|
|
+
|
|
|
+ line = line[1:]
|
|
|
+
|
|
|
+ if len(line) == 0:
|
|
|
+ self.__get_section().add_comment("")
|
|
|
+ return
|
|
|
+
|
|
|
+ if line[0] == " ":
|
|
|
+ line = line[1:]
|
|
|
+
|
|
|
+ self.__get_section().add_comment(line)
|
|
|
+
|