articlib 0.2.9__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.
articlib-0.2.9/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2023 Iñaki Arrondo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.1
2
+ Name: articlib
3
+ Version: 0.2.9
4
+ Summary: Small set of tools and utilities in python. Destined to be use in my personal projects.
5
+ License: MIT
6
+ Author: Artic42
7
+ Author-email: engineer@artic42.com
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: colorama (>=0.4.6,<0.5.0)
16
+ Requires-Dist: pytest (>=9.0.2,<10.0.0)
17
+ Description-Content-Type: text/markdown
18
+
19
+ New documentation been written slowly
20
+
@@ -0,0 +1 @@
1
+ New documentation been written slowly
@@ -0,0 +1,130 @@
1
+ import os
2
+ import shutil
3
+ import logging
4
+ import logUtils as LU
5
+
6
+
7
+ logObj = logging.getLogger()
8
+
9
+
10
+ def deleteFile(path: str) -> None:
11
+ logObj.debug(f"Delete the file on path {path}")
12
+ os.remove(path)
13
+
14
+
15
+ def createFile(path: str) -> None:
16
+ logObj.debug(f"Create file on path {path}")
17
+ file = open(path, "w")
18
+ file.close()
19
+
20
+
21
+ def copyFile(source: str, destination: str) -> None:
22
+ logObj.debug(f"Copy file from {source} to {destination}")
23
+ shutil.copy(source, destination)
24
+
25
+
26
+ def fileExists(path: str) -> bool:
27
+ return os.path.isfile(path)
28
+
29
+
30
+ def getFilesInDirectory(path: str) -> list[str]:
31
+ return os.listdir(path)
32
+
33
+
34
+ def deleteDirectory(path: str) -> None:
35
+ logObj.debug(f"Delete directory on {path}")
36
+ os.rmdir(path)
37
+
38
+
39
+ def deleteDirectoryTree(path: str) -> None:
40
+ logObj.debug(f"Remove entire directory tree in {path}")
41
+ shutil.rmtree(path)
42
+
43
+
44
+ def createDirectory(path: str) -> None:
45
+ logObj.debug(f"Create directory on {path}")
46
+ os.makedirs(path, exist_ok=True)
47
+
48
+
49
+ def directoryExists(path: str) -> bool:
50
+ return os.path.isdir(path)
51
+
52
+
53
+ class FileIO:
54
+ def __init__(self, path: str, readIt: bool = False, log: bool = True) -> None:
55
+ self.log = log
56
+ self.path = path
57
+ if self.log is True:
58
+ logObj.debug(f"Create FileIO object with path {self.path}")
59
+ if readIt is True:
60
+ logObj.info(f"Reading content in path {self.path}")
61
+ self.readFile()
62
+ else:
63
+ logObj.info("Load file as empty without reading")
64
+ self.lines: list[str] = []
65
+
66
+ def readFile(self) -> None:
67
+ filePointer = open(self.path, "r")
68
+ if self.log is True:
69
+ logObj.info(f"Read file in {self.path}")
70
+ LU.logFile(self.path, debugFlag=True)
71
+ self.lines = filePointer.readlines()
72
+ self.lines = [line[:-1] for line in self.lines]
73
+ filePointer.close()
74
+
75
+ def writeFile(self) -> None:
76
+ filePointer = open(self.path, "w")
77
+ for line in self.lines:
78
+ filePointer.write(line + "\n")
79
+ if self.log is True:
80
+ logObj.info(f"Write file in {self.path}")
81
+ LU.logFile(self.path, debugFlag=True)
82
+
83
+ filePointer.close()
84
+
85
+ def appendToFile(self) -> None:
86
+ filePointer = open(self.path, "a")
87
+ for line in self.lines:
88
+ filePointer.write(line + "\n")
89
+ if self.log is True:
90
+ logObj.info(f"Append to file in {self.path}")
91
+ LU.logFile(self.path, debugFlag=True)
92
+ filePointer.close()
93
+
94
+ def addLine(self, line: str) -> None:
95
+ if self.log is True:
96
+ logObj.info(f"Addline: {line}")
97
+ self.lines.append(line)
98
+
99
+ def modifyLine(self, lineNumber: int, line: str) -> None:
100
+ if self.log is True:
101
+ logObj.info(f"Modify line {lineNumber} to {line}")
102
+ self.lines[lineNumber] = line
103
+
104
+ def removeLine(self, lineNumber: int) -> None:
105
+ if self.log is True:
106
+ logObj.info(f"Remove line {lineNumber}")
107
+ logObj.debug(f"Removed content is {self.lines[lineNumber]}")
108
+ del self.lines[lineNumber]
109
+
110
+ def removeLastLine(self) -> None:
111
+ if self.log is True:
112
+ logObj.info("Remove last line")
113
+ logObj.debug(f"Removed content is {self.lines[-1]}")
114
+ del self.lines[-1]
115
+
116
+ def findLine(self, text: str) -> list[int]:
117
+ result: list[int] = []
118
+ for i in range(len(self.lines)):
119
+ if text in self.lines[i]:
120
+ result.append(i)
121
+ return result
122
+
123
+ def findAndReplace(self, find: str, replace: str) -> None:
124
+ if self.log is True:
125
+ logObj.info(f"Find {find} and replace it with {replace}")
126
+ for i in range(len(self.lines)):
127
+ self.lines[i] = self.lines[i].replace(find, replace)
128
+
129
+ def lineCount(self) -> int:
130
+ return len(self.lines)
@@ -0,0 +1,45 @@
1
+ from colorama import Fore, Style
2
+
3
+
4
+ def printRed(text: str) -> None:
5
+ print(Fore.RED + text + Style.RESET_ALL)
6
+
7
+
8
+ def printGreen(text: str) -> None:
9
+ print(Fore.GREEN + text + Style.RESET_ALL)
10
+
11
+
12
+ def printYellow(text: str) -> None:
13
+ print(Fore.YELLOW + text + Style.RESET_ALL)
14
+
15
+
16
+ def printBlue(text: str) -> None:
17
+ print(Fore.BLUE + text + Style.RESET_ALL)
18
+
19
+
20
+ def printMagenta(text: str) -> None:
21
+ print(Fore.MAGENTA + text + Style.RESET_ALL)
22
+
23
+
24
+ def printBold(text: str) -> None:
25
+ print(Style.BRIGHT + text + Style.RESET_ALL)
26
+
27
+
28
+ def printRedBold(text: str) -> None:
29
+ print(Style.BRIGHT + Fore.RED + text + Style.RESET_ALL)
30
+
31
+
32
+ def printGreenBold(text: str) -> None:
33
+ print(Style.BRIGHT + Fore.GREEN + text + Style.RESET_ALL)
34
+
35
+
36
+ def printYellowBold(text: str) -> None:
37
+ print(Style.BRIGHT + Fore.YELLOW + text + Style.RESET_ALL)
38
+
39
+
40
+ def printBlueBold(text: str) -> None:
41
+ print(Style.BRIGHT + Fore.BLUE + text + Style.RESET_ALL)
42
+
43
+
44
+ def printMagentaBold(text: str) -> None:
45
+ print(Style.BRIGHT + Fore.MAGENTA + text + Style.RESET_ALL)
@@ -0,0 +1,139 @@
1
+ from datetime import datetime
2
+
3
+ YYYYMMDD = 1
4
+ DDMMYYYY = 2
5
+ MMDDYYYY = 3
6
+
7
+
8
+ class createDate:
9
+ def __init__(self, mode: int) -> None:
10
+ self.mode = mode
11
+
12
+ def setToNow(self) -> None:
13
+ date = datetime.now()
14
+ self.year = int(date.year)
15
+ self.month = int(date.month)
16
+ self.day = int(date.day)
17
+ self.hour = int(date.hour)
18
+ self.minute = int(date.minute)
19
+ self.second = int(date.second)
20
+ self.calculateStringDate()
21
+ self.calculateStringTime()
22
+
23
+ def setTo(
24
+ self, year: int, month: int, day: int, hour: int, minute: int, second: int
25
+ ) -> None:
26
+ self.year = year
27
+ self.month = month
28
+ self.day = day
29
+ self.hour = hour
30
+ self.minute = minute
31
+ self.second = second
32
+ self.calculateStringDate()
33
+ self.calculateStringTime()
34
+
35
+ def setToString(self, string: str) -> None:
36
+ stringList: list[str] = string.split(" ")
37
+ date: str = stringList[0]
38
+ time: str = stringList[1]
39
+ self.dateString = date
40
+ self.timeString = time
41
+ self.calculateDate()
42
+ self.calculateTime()
43
+
44
+ def calculateDate(self) -> None:
45
+ if self.mode == YYYYMMDD:
46
+ self.year = int(self.dateString[0:4])
47
+ self.month = int(self.dateString[5:7])
48
+ self.day = int(self.dateString[8:10])
49
+ elif self.mode == DDMMYYYY:
50
+ self.day = int(self.dateString[0:2])
51
+ self.month = int(self.dateString[3:5])
52
+ self.year = int(self.dateString[6:10])
53
+ elif self.mode == MMDDYYYY:
54
+ self.month = int(self.dateString[0:2])
55
+ self.day = int(self.dateString[3:5])
56
+ self.year = int(self.dateString[6:10])
57
+ else:
58
+ raise ValueError("Invalid mode")
59
+
60
+ def calculateTime(self) -> None:
61
+ self.hour = int(self.timeString[0:2])
62
+ self.minute = int(self.timeString[3:5])
63
+ self.second = int(self.timeString[6:8])
64
+
65
+ def calculateStringDate(self) -> None:
66
+ if self.mode == YYYYMMDD:
67
+ self.dateString = str(self.year) + "/"
68
+ self.dateString += str(self.month).zfill(2) + "/"
69
+ self.dateString += str(self.day).zfill(2)
70
+ elif self.mode == DDMMYYYY:
71
+ self.dateString = str(self.day).zfill(2) + "/"
72
+ self.dateString += str(self.month).zfill(2) + "/"
73
+ self.dateString += str(self.year)
74
+ elif self.mode == MMDDYYYY:
75
+ self.dateString = str(self.month).zfill(2) + "/"
76
+ self.dateString += str(self.day).zfill(2) + "/"
77
+ self.dateString += str(self.year)
78
+ else:
79
+ raise ValueError("Invalid mode")
80
+
81
+ def calculateStringTime(self) -> None:
82
+ self.timeString = str(self.hour).zfill(2) + ":"
83
+ self.timeString += str(self.minute).zfill(2) + ":"
84
+ self.timeString += str(self.second).zfill(2)
85
+
86
+ def setMode(self, mode: int) -> None:
87
+ self.mode = mode
88
+ self.calculateStringDate()
89
+
90
+ # Output values
91
+ def getDateTimePathFormat(self) -> str:
92
+ if self.mode == YYYYMMDD:
93
+ dateString = (
94
+ str(self.year) + str(self.month).zfill(2) + str(self.day).zfill(2)
95
+ )
96
+ elif self.mode == DDMMYYYY:
97
+ dateString = (
98
+ str(self.day).zfill(2) + str(self.month).zfill(2) + str(self.year)
99
+ )
100
+ elif self.mode == MMDDYYYY:
101
+ dateString = (
102
+ str(self.month).zfill(2) + str(self.day).zfill(2) + str(self.year)
103
+ )
104
+ else:
105
+ raise ValueError("Invalid mode")
106
+ timeString = str(self.hour).zfill(2)
107
+ timeString += str(self.minute).zfill(2)
108
+ timeString += str(self.second).zfill(2)
109
+ return f"{dateString}_{timeString}"
110
+
111
+ def getDate(self) -> str:
112
+ return self.dateString
113
+
114
+ def getTime(self) -> str:
115
+ return self.timeString
116
+
117
+ def getDateTime(self) -> str:
118
+ return self.dateString + " " + self.timeString
119
+
120
+ def getYear(self) -> int:
121
+ return self.year
122
+
123
+ def getMonth(self) -> int:
124
+ return self.month
125
+
126
+ def getDay(self) -> int:
127
+ return self.day
128
+
129
+ def getHour(self) -> int:
130
+ return self.hour
131
+
132
+ def getMinute(self) -> int:
133
+ return self.minute
134
+
135
+ def getSecond(self) -> int:
136
+ return self.second
137
+
138
+ def getMode(self) -> int:
139
+ return self.mode
@@ -0,0 +1,61 @@
1
+ import random
2
+ import logging
3
+
4
+
5
+ log = logging.getLogger()
6
+
7
+
8
+ class dice:
9
+ def __init__(self, size: int = 6, log: bool = True) -> None:
10
+ self.log: bool = log
11
+ self.size: int = size
12
+
13
+ def setSize(self, size: int) -> None:
14
+ self.size = size
15
+
16
+ def setLog(self, log: bool) -> None:
17
+ self.log = log
18
+
19
+ def roll(self) -> int:
20
+ result: int = random.randint(1, self.size)
21
+ if self.log is True:
22
+ log.info(f"Dice of size {self.size} rolled result is {result}")
23
+ return result
24
+
25
+
26
+ class customDice:
27
+ def __init__(self, faces: list[str], name: str, log: bool = True) -> None:
28
+ self.faces: list[str] = faces
29
+ self.name: str = name
30
+ self.log: bool = log
31
+ self.size: int = len(faces)
32
+
33
+ def roll(self) -> str:
34
+ face: str = random.choice(self.faces)
35
+ if self.log is True:
36
+ log.info(f"{self.name} dice roll result is {face}")
37
+ return face
38
+
39
+
40
+ class dicePool:
41
+ def __init__(self, diceList: list[dice], log: bool = True) -> None:
42
+ self.log: bool = log
43
+ self.diceList: list[dice] = diceList
44
+
45
+ def roll(self) -> list[int]:
46
+ result: list[int] = [d.roll() for d in self.diceList]
47
+ if self.log is True:
48
+ log.info(f"Dice pool rolled with the following result {result}")
49
+ return result
50
+
51
+ def rollSum(self) -> int:
52
+ result: int = sum(self.roll())
53
+ if self.log is True:
54
+ log.info(f"Dice pool sum is {result}")
55
+ return result
56
+
57
+ def rollSuccesses(self, target: int) -> int:
58
+ result: int = sum([1 for roll in self.roll() if roll >= target])
59
+ if self.log is True:
60
+ log.info(f"Roll dice pool looking for {target}, {result} successes")
61
+ return result
@@ -0,0 +1,132 @@
1
+ import json
2
+ import socket
3
+ import logging
4
+ import mmap
5
+ from typing import Any
6
+ from datetime import datetime
7
+
8
+
9
+ log = logging.getLogger()
10
+
11
+
12
+ class JsonFile:
13
+ def __init__(self, path: str,
14
+ type: str = "",
15
+ size: int = 1024,
16
+ read: bool = False,
17
+ write: bool = False) -> None:
18
+ self.clock: datetime = datetime.now()
19
+ self.content: dict[str, Any] = {}
20
+ self._setHostname()
21
+ self.read: bool = read
22
+ self.write: bool = write
23
+
24
+ if read is False and write is False:
25
+ msg = "No mode selected at class creation"
26
+ log.error(msg)
27
+ raise ValueError(msg)
28
+
29
+ if read is True and write is True:
30
+ msg = "Both mode selected at class creation, only one allowed"
31
+ log.error(msg)
32
+ raise ValueError(msg)
33
+
34
+ if type == "":
35
+ self._setType(path)
36
+ else:
37
+ self._setType(type)
38
+
39
+ self.size = size
40
+ self.path = path
41
+
42
+ if write is True:
43
+ filePtr = open(path, "wb")
44
+ filePtr.write(b"\x00" * size)
45
+ filePtr.close()
46
+ del filePtr
47
+
48
+ if read is True:
49
+ filePtr2 = open(path, "r+b")
50
+ filePtr2.seek(size-1)
51
+ filePtr2.write(b"\x00")
52
+ filePtr2.close()
53
+ del filePtr2
54
+
55
+ self.filePtr = open(path, "r+b")
56
+ self.fmap = mmap.mmap(self.filePtr.fileno(), size)
57
+
58
+ def __del__(self) -> None:
59
+ if hasattr(self, "fmap"):
60
+ self.fmap.close()
61
+ if self.read is True:
62
+ return
63
+ if self.write is True:
64
+ self.bufferedWrite()
65
+
66
+ def _setHostname(self) -> None:
67
+ self.content["Hostname"] = socket.gethostname()
68
+
69
+ def _setType(self, type: str) -> None:
70
+ self.content["type"] = type
71
+
72
+ def _setDate(self) -> None:
73
+ self.content["year"] = int(self.clock.year)
74
+ self.content["month"] = int(self.clock.month)
75
+ self.content["day"] = int(self.clock.day)
76
+
77
+ def _setTime(self) -> None:
78
+ self.content["hour"] = int(self.clock.hour)
79
+ self.content["minute"] = int(self.clock.minute)
80
+ self.content["second"] = int(self.clock.second)
81
+
82
+ def bufferedWrite(self) -> None:
83
+ FilePtr = open(self.path, "w")
84
+ json.dump(self.content, FilePtr, indent=4)
85
+ FilePtr.close()
86
+
87
+ def writeData(self, data: dict[str, Any]) -> int:
88
+ if self.write is False:
89
+ log.error("File was open without write mode and can't be written")
90
+ return 3
91
+
92
+ self.clock = datetime.now()
93
+ self._setDate()
94
+ self._setTime()
95
+ self.content["data"] = data
96
+
97
+ # Convert dict into bytes
98
+ file_bytes = json.dumps(self.content, indent=4).encode()
99
+
100
+ if len(file_bytes) > self.size:
101
+ log.error("File too small, too much data to dump")
102
+ return 1
103
+
104
+ # Clear memory map
105
+ self.fmap.seek(0)
106
+ self.fmap.write(b"\x00" * self.size)
107
+
108
+ # Write data
109
+ self.fmap.seek(0)
110
+ self.fmap.write(file_bytes)
111
+
112
+ return 0
113
+
114
+ def readData(self) -> int:
115
+ if self.read is False:
116
+ log.error("File was open without read mode and can't be read")
117
+ return 2
118
+
119
+ # Read the entire memory-mapped region (this IS the file)
120
+ raw = self.fmap[:]
121
+
122
+ # Stop at the first null byte (padding begins here)
123
+ json_bytes = raw.split(b"\x00", 1)[0]
124
+
125
+ # If file is empty or only padding
126
+ if not json_bytes.strip():
127
+ log.error("File is empty and can't be read")
128
+ return 3
129
+
130
+ # Decode and parse JSON
131
+ self.content = json.loads(json_bytes.decode())
132
+ return 0
@@ -0,0 +1,47 @@
1
+ import logging
2
+ import articFileUtils as FU
3
+
4
+
5
+ log = logging.getLogger()
6
+
7
+
8
+ def logFile(path: str, debugFlag: bool = False) -> None:
9
+ if debugFlag is True:
10
+ logFunc = log.debug
11
+ else:
12
+ logFunc = log.info
13
+
14
+ logFunc("===================================================")
15
+ logFunc(" Log contents of file")
16
+ logFunc(f" Path: {path}")
17
+ logFunc("===================================================")
18
+ if FU.fileExists(path):
19
+ FP = open(path, "r")
20
+ lines = FP.readlines()
21
+ for line in lines:
22
+ logFunc(line[:-1])
23
+ else:
24
+ log.error("File doesn't exist")
25
+ logFunc("===================================================")
26
+
27
+
28
+ def logTestStart(title: str) -> None:
29
+ logSepDoubleLine()
30
+ log.info(f" {title}")
31
+ logSepDoubleLine()
32
+
33
+
34
+ def logTestEnd() -> None:
35
+ logSepDoubleLine()
36
+ log.info(" Test finished")
37
+ logSepDoubleLine()
38
+ log.info("")
39
+ log.info("")
40
+
41
+
42
+ def logSepDoubleLine() -> None:
43
+ log.info("===================================================")
44
+
45
+
46
+ def logSepLine() -> None:
47
+ log.info("---------------------------------------------------")
File without changes
@@ -0,0 +1,72 @@
1
+ import sqlite3
2
+ import logging
3
+ from typing import Any
4
+
5
+
6
+ log = logging.getLogger()
7
+
8
+
9
+ class sqliteEngine:
10
+ def __init__(self, dbPath: str):
11
+ self.con = sqlite3.connect(dbPath)
12
+ self.cursor = self.con.cursor()
13
+
14
+ def executeCommand(self, command: str) -> None:
15
+ log.debug(f"Executing command: {command}")
16
+ self.cursor.execute(command)
17
+
18
+ def createTable(self, name: str, columns: str) -> None:
19
+ self.executeCommand(f"CREATE TABLE {name} ({columns});")
20
+
21
+ def addColumn(self, table: str, column: str) -> None:
22
+ self.executeCommand(f"ALTER TABLE {table} ADD COLUMN {column};")
23
+
24
+ def deleteColumn(self, table: str, column: str) -> None:
25
+ self.executeCommand(f"ALTER TABLE {table} DROP COLUMN {column}")
26
+
27
+ def addEntry(self, table: str, columns: str, values: str) -> None:
28
+ self.executeCommand(f"INSERT INTO {table} ({columns}) VALUES ({values});")
29
+
30
+ def updateEntry(self, table: str, columns: str, values: str, condition: str) -> None:
31
+ self.executeCommand(
32
+ f'UPDATE {table} SET {columns} = "{values}" WHERE {condition};'
33
+ )
34
+
35
+ def deleteEntry(self, table: str, condition: str) -> None:
36
+ self.executeCommand(f"DELETE FROM {table} WHERE {condition};")
37
+
38
+ def readEntry(self, table: str, columns: str) -> list[Any]:
39
+ self.executeCommand(f"SELECT {columns} FROM {table};")
40
+ result = self.cursor.fetchall()
41
+ log.debug(f"Read entry: {result}")
42
+ return result
43
+
44
+ def readNumberOfEntries(self, table: str) -> Any:
45
+ self.executeCommand(f"SELECT COUNT(*) FROM {table};")
46
+ result = self.cursor.fetchall()
47
+ log.debug(f"Read number of entries: {result}")
48
+ return result[0][0]
49
+
50
+ def readEntryFiltered(self, table: str, columns: str, filter: str) -> list[Any]:
51
+ self.executeCommand(f"SELECT {columns} FROM {table} WHERE {filter};")
52
+ result = self.cursor.fetchall()
53
+ log.debug(f"Read entry: {result}")
54
+ return result
55
+
56
+ def entryExistsOnTable(self, table: str, condition: str) -> bool:
57
+ self.executeCommand(f"SELECT * FROM {table} WHERE {condition};")
58
+ entry = self.cursor.fetchall()
59
+ if len(entry) != 0:
60
+ return True
61
+ else:
62
+ return False
63
+
64
+ def deleteEntryFromTable(self, table: str, condition: str) -> None:
65
+ self.executeCommand(f"DELETE FROM {table} WHERE {condition};")
66
+
67
+ def commit(self) -> None:
68
+ self.con.commit()
69
+
70
+ def commitClose(self) -> None:
71
+ self.commit()
72
+ self.con.close()
@@ -0,0 +1,32 @@
1
+ [tool.poetry]
2
+ name = "articlib"
3
+ version = "0.2.9"
4
+ description = "Small set of tools and utilities in python. Destined to be use in my personal projects."
5
+ authors = ["Artic42 <engineer@artic42.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+
9
+ [tool.poetry.dependencies]
10
+ python = "^3.10"
11
+ colorama = "^0.4.6"
12
+ pytest = "^9.0.2"
13
+
14
+ [tool.poetry.group.dev.dependencies]
15
+ flake8-pyproject = "^1.2.3"
16
+ flake8 = "^7.1.1"
17
+ mypy = "^1.11.2"
18
+ black = "^24.8.0"
19
+ freezegun = "^1.5.5"
20
+
21
+
22
+ [tool.poetry.group.deb.dependencies]
23
+ types-colorama = "^0.4.15.20250801"
24
+
25
+ [tool.mypy]
26
+ python_version = "3.13"
27
+ strict = true
28
+
29
+
30
+ [build-system]
31
+ requires = ["poetry-core"]
32
+ build-backend = "poetry.core.masonry.api"