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

Continue working on library.

cixo 10 сар өмнө
parent
commit
bb5e676101

+ 11 - 0
03-pini.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

+ 1 - 0
src/CxPini/__init__.py

@@ -2,3 +2,4 @@ from .exception import pini_exception
 from .exception import pini_type_exception
 from .key import key
 from .section import section
+from .pini import pini

+ 15 - 36
src/CxPini/key.py

@@ -1,24 +1,16 @@
 from .exception import pini_exception
 from .exception import pini_type_exception
+from .line import line
 
-class key:
+class key(line):
     def __init__(self):
-        self.__name: str | None = None
+        super().__init__()
         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:
@@ -26,16 +18,6 @@ class key:
 
         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:
@@ -48,16 +30,6 @@ class key:
 
         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
@@ -79,16 +51,16 @@ class key:
 
         return self.__value
 
-    def __str__(self) -> str:
+    def render(self) -> str:
         comment = ""
         
-        if self.__comment is not None:
-            comment = "# " + self.__comment
+        if self.comment is not None:
+            comment = "# " + self.comment
 
-        if self.__name is None:
+        if self.name is None:
             return comment
 
-        content = self.__name + " = "
+        content = self.name + " = "
 
         if self.__value is not None:
             content = content + str(self.__value)
@@ -102,3 +74,10 @@ class key:
 
         return content
 
+    def clone(self):
+        copy = key()
+        copy.name = self.name
+        copy.value = self.value
+        copy.comment = self.comment
+
+        return copy

+ 56 - 0
src/CxPini/line.py

@@ -0,0 +1,56 @@
+class line:
+    def __init__(self):
+        self.__name: str | None = None
+        self.__comment: str | None = None
+
+    @property
+    def name(self) -> str | None:
+        return self.__name
+
+    @name.setter
+    def name(self, target: str | None) -> None:
+        if type(target) is str:
+            self.__name = target
+            return
+
+        if target is None:
+            self.__name = None
+            return
+
+        raise TypeError("New name for the line must be str or None.")
+
+    @property
+    def comment(self) -> str | None:
+        return self.__comment
+
+    @comment.setter
+    def comment(self, target: str | None) -> None:
+        if type(target) is str:
+            self.__comment = target
+            return
+
+        if target is None:
+            self.__comment = None
+            return
+
+        raise TypeError("New comment must be str or None.")
+
+    def add_comment(self, target: str) -> str:
+        if type(target) is not str:
+            raise TypeError("New content of the comment must be str.")
+
+        if type(self.__comment) is not str:
+            self.__comment = ""
+
+        self.__comment = self.__comment + target
+
+        return self.__comment
+
+    def clean_comment(self) -> None:
+        self.__comment = None
+
+    def render(self) -> str:
+        raise Exception("It is implemented in the key or section class.")
+
+    def __str__(self) -> str:
+        return self.render()

+ 98 - 2
src/CxPini/pini.py

@@ -1,3 +1,99 @@
+from .section import section
+from .exception import pini_exception
+
 class pini:
-    def __init__(self, target = None):
-        pass
+    def __init__(self):
+        self.__sections = list()
+
+    def get(self, target: str) -> section | None:
+        if type(target) is not str:
+            raise TypeError("Name of the section to get must be str.")
+
+        for count in self.__sections:
+            if count.name == target:
+                return count
+        
+        return None
+
+    def exists(self, target: str) -> bool:
+        return self.get(target) is not None
+
+    @property
+    def global_section(self) -> section | None:
+        for count in self.__sections:
+            if count.is_global:
+                return count
+
+        return None
+
+    @property
+    def has_global(self) -> bool:
+        return self.global_section is not None
+
+    def add(self, target: section) -> None:
+        if type(target) is not section:
+            raise TypeError("New section must be in section type.")
+
+        if target.is_global and not self.has_global:
+            self.__sections.append(target)
+            return
+
+        if not target.is_global and not self.exists(target.name):
+            self.__sections.append(target)
+            return 
+
+        if target.is_global:
+            raise pini_exception("This config already has global section.")
+
+        raise pini_exception("Section " + target.name + " already exists.")
+
+    def drop_global(self) -> section | None:
+        index = -1
+
+        for count in range(len(self.__sections)):
+            if self.__sections[count].is_global:
+                index = count
+                break
+
+        if index == -1:
+            return self.__sections.pop(index)
+
+        return
+
+    def drop(self, target: section | str) -> section | None:
+        if type(target) is section and target.is_global:
+            return self.drop_global()
+
+        if type(target) is section:
+            target = target.name
+
+        if type(target) is not str:
+            raise TypeError("Section to drop must be str or section.")
+        
+        index = -1
+
+        for count in range(len(self.__sections)):
+            if self.__sections[count].name == target:
+                index = count
+                break
+
+        if index != -1:
+            return self.__sections.pop(index)
+
+    def render(self) -> str:
+        summary = ""
+
+        if self.has_global:
+            summary = str(self.global_section)
+
+        for count in self.__sections:
+            if count.is_global:
+                continue 
+
+            summary = summary + str(count)
+
+        return summary
+
+    def __str__(self) -> str:
+        return self.render()
+            

+ 26 - 36
src/CxPini/section.py

@@ -2,40 +2,16 @@ import textwrap
 
 from .exception import pini_exception
 from .key import key
+from .line import line
 
-class section:
+class section(line):
     def __init__(self):
-        self.__name: str | None = None
-        self.__comment: str | None = None    
+        super().__init__()
         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
+        return self.name is None
 
     def get(self, target: str) -> key | None:
         if type(target) is not str:
@@ -44,7 +20,7 @@ class section:
         target.strip()
 
         if len(target) == 0:
-            raise TypeError("Ket name to get can not be empty.")
+            raise TypeError("Key name to get can not be empty.")
 
         for count in self.__keys:
             if count.name == target:
@@ -55,7 +31,21 @@ class section:
     def exists(self, target: str) -> bool:
         return self.get(target) is not None
 
-    def add_key(self, target: key) -> None:
+    def drop(self, target: key | str) -> key | None:
+        if type(target) is key:
+            target = target.name
+
+        index = -1
+
+        for count in range(len(self.__keys)):
+            if self.__keys[count].name == target:
+                index = count
+                break
+
+        if index != -1:
+            return self.__keys.pop(index)
+
+    def add(self, target: key) -> None:
         if type(target) is not key:
             raise TypeError("New key must be instance of key.")
 
@@ -66,17 +56,17 @@ class section:
 
             raise pini_exception(error)
 
-        self.__keys.append(target)
+        self.__keys.append(target.clone())
 
-    def __str__(self) -> str:
+    def render(self) -> str:
         content = ""
         comments = list()
         
-        if self.__name is not None:
-            content = "[" + self.__name + "]\n"
+        if self.name is not None:
+            content = "[" + self.name + "]\n"
         
-        if self.__comment is not None:
-            comments = textwrap.wrap(self.__comment, 77)
+        if self.comment is not None:
+            comments = textwrap.wrap(self.comment, 77)
 
         for count in comments:
             content = content + "# " + count + "\n"

+ 10 - 5
tests/02-section.py

@@ -29,20 +29,25 @@ 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)
+sample.add(first)
+sample.add(second)
+sample.add(last)
 
 print(sample)
 
 if sample.get("first").value != 10:
     print("Can not get first.")
 
-if not sample.exists("second"):
+if not sample.exists("other"):
     print("Second can not be found.")
 
-if not sample.get("last").value != 20:
+if sample.get("last").value != 20:
     print("Last return bad content.")
 
 if sample.exists("jiojoijio"):
     print("Key which not exists is returned.")
+
+sample.drop(last)
+sample.drop("other")
+
+print(sample)

+ 52 - 0
tests/03-pini.py

@@ -0,0 +1,52 @@
+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
+
+f1 = pini.key()
+f1.name = "x"
+f1.value = 20
+
+f2 = pini.key()
+f2.name = "y"
+f2.value = 30
+
+f3 = pini.key()
+f3.name = "z"
+
+f4 = pini.key()
+f4.name = "a"
+f4.value = "VALUE"
+f4.comment = "This is key comment."
+
+global_section = pini.section()
+global_section.comment = "This is global section."
+global_section.add(f2)
+global_section.add(f1)
+
+other_section = pini.section()
+other_section.name = "Other"
+other_section.comment = "This is other section."
+other_section.add(f3)
+other_section.add(f4)
+other_section.add(f1)
+
+last_section = pini.section()
+last_section.name = "last"
+last_section.comment = "This is very last section."
+last_section.add(f1)
+last_section.add(f2)
+
+test = pini.pini()
+test.add(global_section)
+test.add(other_section)
+test.add(last_section)
+
+print(test)

+ 19 - 0
tests/sample.ini

@@ -0,0 +1,19 @@
+# This is global section.
+
+y = 30
+x = 20
+
+[Other]
+# This is other section.
+
+### z = 
+a = VALUE   # This is key comment.
+x = 20
+
+[last]
+# This is very last section.
+
+x = 20
+y = 30
+
+