Эх сурвалжийг харах

Start working on the project.

cixo 10 сар өмнө
parent
commit
7e56c678b7

+ 32 - 0
pyproject.toml

@@ -0,0 +1,32 @@
+[project]
+name = "CxPini"
+version = "1.0.0"
+description = "This library is INI parser, which store users comments."
+readme = "README.md"
+requires-python = ">=3.1"
+
+authors = [
+    { name = "Cixo", email = "[email protected]" }
+]
+
+classifiers = [
+    "Programming Language :: Python :: 3",
+    "License :: OSI Approved :: MIT License",
+    "Operating System :: OS Independent",
+]
+
+[project.urls]
+Homepage = "https://git.cixoelectronic.pl/cixo-electronic/cx-pini/wiki"
+Issues = "https://git.cixoelectronic.pl/cixo-electronic/cx-pini/issues"
+
+[build-system]
+build-backend = "setuptools.build_meta"
+
+requires = [
+    "setuptools>=60.0"
+]
+
+[tool.setuptools]
+packages = [
+    "cx-pins"
+]

+ 4 - 0
src/CxPini/__init__.py

@@ -0,0 +1,4 @@
+from .exception import pini_exception
+from .exception import pini_type_exception
+from .key import key
+from .section import section

+ 5 - 0
src/CxPini/exception.py

@@ -0,0 +1,5 @@
+class pini_exception(Exception):
+    pass
+
+class pini_type_exception(TypeError):
+    pass

+ 104 - 0
src/CxPini/key.py

@@ -0,0 +1,104 @@
+from .exception import pini_exception
+from .exception import pini_type_exception
+
+class key:
+    def __init__(self):
+        self.__name: str | None = None
+        self.__value: str | int | float | None = None
+        self.__comment: str | None = None
+
+    @property
+    def name(self) -> str | None:
+        return self.__name
+
+    @property
+    def value(self) -> str | int | float | None:
+        return self.__value
+
+    @property
+    def comment(self) -> str | None:
+        return self.__comment
+
+    @property
+    def value_type(self) -> str:
+        if self.__value is None:
+            return "None"
+
+        return type(self.__value).__name__
+
+    @name.setter
+    def name(self, target: str | None) -> None:
+        if type(target) is str:
+            target = target.strip()
+
+        if target is not None and type(target) is not str:
+            raise TypeError("Name of the key must be str or None.")
+
+        self.__name = target
+
+    @value.setter
+    def value(self, target: str | int | float | None) -> None:
+        if type(target) is str:
+            self.__value = target.strip()
+            return
+    
+        if type(target) is int or type(target) is float or target is None:
+            self.__value = target
+            return
+
+        raise TypeError("Value must be str, int, float or None.")
+
+    @comment.setter
+    def comment(self, target: str | None) -> None:
+        if type(target) is str:
+            target = target.strip()
+
+        if type(target) is not str and target is not None:
+            raise TypeError("Comment must be str or None.")
+
+        self.__comment = target
+
+    def get(self, empty: str | int | float | None) -> str | int | float | None:
+        checked = type(empty) is str
+        checked = checked or type(empty) is int
+        checked = checked or type(empty) is float
+        checked = checked or empty is None
+
+        if not checked:
+            raise TypeError("Default value for empty key type is not valid.")
+
+        if self.__value is None:
+            return empty
+
+        if type(empty) is not type(self.__value):
+            error = "Type of the " + self.name + " is not valid. "
+            error = error + "It must be in " + type(empty).__name__ + ". "
+            error = error + "It is " + type(self.__value).__name__ + "."
+
+            raise pini_type_exception(error)
+
+        return self.__value
+
+    def __str__(self) -> str:
+        comment = ""
+        
+        if self.__comment is not None:
+            comment = "# " + self.__comment
+
+        if self.__name is None:
+            return comment
+
+        content = self.__name + " = "
+
+        if self.__value is not None:
+            content = content + str(self.__value)
+
+        if self.__value is None:
+            content = "### " + content
+        
+        if len(comment) > 0:
+            content = content + (" " * (4 - (len(content) % 4)))
+            content = content + comment
+
+        return content
+

+ 5 - 0
src/CxPini/parser.py

@@ -0,0 +1,5 @@
+from .pini_exception import pini_exception
+
+class parser:
+    
+

+ 3 - 0
src/CxPini/pini.py

@@ -0,0 +1,3 @@
+class pini:
+    def __init__(self, target = None):
+        pass

+ 95 - 0
src/CxPini/section.py

@@ -0,0 +1,95 @@
+import textwrap
+
+from .exception import pini_exception
+from .key import key
+
+class section:
+    def __init__(self):
+        self.__name: str | None = None
+        self.__comment: str | None = None    
+        self.__keys: list[key] = list()
+
+    @property
+    def is_global(self) -> bool:
+        return self.__name is None
+
+    @property
+    def name(self) -> str | None:
+        return self.__name
+
+    @name.setter
+    def name(self, target: str | None) -> None:
+        if type(target) is str:
+            target = target.strip()
+
+        if type(target) is not str and target is not None:
+            raise TypeError("Section name must be str, or None for global.")
+
+        self.__name = target
+
+    @property 
+    def comment(self) -> str | None:
+        return self.__comment
+
+    def add_comment(self, content: str) -> None:
+        if self.__comment is None:
+            self.__comment = ""
+        
+        self.__comment = self.__comment + content
+
+    def get(self, target: str) -> key | None:
+        if type(target) is not str:
+            raise TypeError("Key name to get must me str.")
+        
+        target.strip()
+
+        if len(target) == 0:
+            raise TypeError("Ket name to get can not be empty.")
+
+        for count in self.__keys:
+            if count.name == target:
+                return count
+
+        return None
+
+    def exists(self, target: str) -> bool:
+        return self.get(target) is not None
+
+    def add_key(self, target: key) -> None:
+        if type(target) is not key:
+            raise TypeError("New key must be instance of key.")
+
+        if self.exists(target.name):
+            error = "Target key " 
+            error = error + target.name + " " 
+            error = error + "already exists."
+
+            raise pini_exception(error)
+
+        self.__keys.append(target)
+
+    def __str__(self) -> str:
+        content = ""
+        comments = list()
+        
+        if self.__name is not None:
+            content = "[" + self.__name + "]\n"
+        
+        if self.__comment is not None:
+            comments = textwrap.wrap(self.__comment, 77)
+
+        for count in comments:
+            content = content + "# " + count + "\n"
+
+        if len(comments) > 0:
+            content = content + "\n"
+
+        for count in self.__keys:
+            content = content + str(count) + "\n"
+
+        if len(self.__keys) > 0:
+            content = content + "\n"
+
+        return content
+    
+        

+ 11 - 0
tests/00-sample.py

@@ -0,0 +1,11 @@
+import sys
+import pathlib
+
+test_file = pathlib.Path(__file__).absolute()
+test_dir = test_file.parent
+project_dir = test_dir.parent
+source_dir = project_dir / "src"
+
+sys.path.append(str(source_dir))
+
+import CxPini as pini

+ 54 - 0
tests/01-key.py

@@ -0,0 +1,54 @@
+import sys
+import pathlib
+
+test_file = pathlib.Path(__file__).absolute()
+test_dir = test_file.parent
+project_dir = test_dir.parent
+source_dir = project_dir / "src"
+
+sys.path.append(str(source_dir))
+
+import CxPini as pini
+
+check = pini.key()
+count = 0
+
+def dump():
+    global count
+    global check
+
+    count = count + 1
+
+    print("Dump: " + str(count))
+    print("Key: " + str(check.name))
+    print("Value: " + str(check.value))
+    print("Value type: " + str(check.value_type))
+    print("Comment: " + str(check.comment))
+    print("Result: ")
+    print(str(check))
+    print()
+
+
+dump()
+check.comment = "Sample"
+dump()
+check.name = "key"
+dump()
+check.value = "      value"
+dump()
+check.value = 10
+dump()
+check.name = None
+dump()
+check.name = "key"
+dump()
+print("Get result: " + str(check.get(20)))
+print()
+check.value = "other"
+dump()
+print("Get result: " + str(check.get("def")))
+print()
+check.value = None
+dump()
+print("Get result: " + str(check.get("def")))
+print()

+ 48 - 0
tests/02-section.py

@@ -0,0 +1,48 @@
+import sys
+import pathlib
+
+test_file = pathlib.Path(__file__).absolute()
+test_dir = test_file.parent
+project_dir = test_dir.parent
+source_dir = project_dir / "src"
+
+sys.path.append(str(source_dir))
+
+import CxPini as pini
+
+first = pini.key()
+first.name = "first"
+first.value = 10
+
+second = pini.key()
+second.name = "other"
+second.value = "This is other key"
+
+last = pini.key()
+last.name = "last"
+last.value = 20
+last.comment = "And with comment"
+
+sample = pini.section()
+sample.add_comment("This is very basic library. ")
+sample.add_comment("It could be used as very very very nice. ")
+sample.add_comment("It is possible to split this very long comments auto.")
+sample.add_comment("I think it is very nice. You have not to do it Yourself.")
+sample.name = "Section"
+sample.add_key(first)
+sample.add_key(second)
+sample.add_key(last)
+
+print(sample)
+
+if sample.get("first").value != 10:
+    print("Can not get first.")
+
+if not sample.exists("second"):
+    print("Second can not be found.")
+
+if not sample.get("last").value != 20:
+    print("Last return bad content.")
+
+if sample.exists("jiojoijio"):
+    print("Key which not exists is returned.")