quick-ini 3.0__tar.gz → 3.1.4__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.
- quick_ini-3.1.4/LICENSE +21 -0
- quick_ini-3.1.4/PKG-INFO +72 -0
- quick_ini-3.1.4/README.md +36 -0
- {quick_ini-3.0 → quick_ini-3.1.4}/pyproject.toml +2 -2
- {quick_ini-3.0 → quick_ini-3.1.4}/quick_ini/__init__.py +1 -1
- {quick_ini-3.0 → quick_ini-3.1.4}/quick_ini/quick_ini.py +230 -229
- quick_ini-3.1.4/quick_ini.egg-info/PKG-INFO +72 -0
- {quick_ini-3.0 → quick_ini-3.1.4}/quick_ini.egg-info/SOURCES.txt +4 -1
- {quick_ini-3.0 → quick_ini-3.1.4}/quick_ini.egg-info/top_level.txt +1 -0
- {quick_ini-3.0 → quick_ini-3.1.4}/setup.cfg +4 -4
- quick_ini-3.1.4/setup.py +35 -0
- quick_ini-3.1.4/tests/__init__.py +1 -0
- quick_ini-3.1.4/tests/test_quickini.py +91 -0
- quick_ini-3.0/PKG-INFO +0 -8
- quick_ini-3.0/README.md +0 -0
- quick_ini-3.0/quick_ini.egg-info/PKG-INFO +0 -8
- quick_ini-3.0/setup.py +0 -13
- {quick_ini-3.0 → quick_ini-3.1.4}/quick_ini.egg-info/dependency_links.txt +0 -0
quick_ini-3.1.4/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 OllieZ-Mods
|
|
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.
|
quick_ini-3.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quick_ini
|
|
3
|
+
Version: 3.1.4
|
|
4
|
+
Summary: A library for reading from and writing to .ini formatted files
|
|
5
|
+
Home-page: https://github.com/olliez-mods/Quick-Ini
|
|
6
|
+
Author: OllieZ-Mods
|
|
7
|
+
Author-email: socksinthewash@gmail.com
|
|
8
|
+
Project-URL: Bug Reports, https://github.com/olliez-mods/Quick-Ini/issues
|
|
9
|
+
Project-URL: Source, https://github.com/olliez-mods/Quick-Ini
|
|
10
|
+
Keywords: ini config configuration parser file
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Requires-Python: >=3.7
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: keywords
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
Dynamic: project-url
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
Dynamic: summary
|
|
36
|
+
|
|
37
|
+
# QuickINI
|
|
38
|
+
|
|
39
|
+
A simple and fast INI file parser for Python with support for loading from URLs and automatic type conversion.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install quickini
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from quickini import QuickIni
|
|
51
|
+
|
|
52
|
+
# Load from file
|
|
53
|
+
QuickIni.load_file("config.ini")
|
|
54
|
+
|
|
55
|
+
# Load from URL
|
|
56
|
+
QuickIni.load_file("https://example.com/config.ini")
|
|
57
|
+
|
|
58
|
+
# Get values with automatic type conversion
|
|
59
|
+
debug = QuickIni.get_value("debug", False) # Returns boolean
|
|
60
|
+
port = QuickIni.get_value("port", 8080) # Returns integer
|
|
61
|
+
|
|
62
|
+
# Write values back to file
|
|
63
|
+
QuickIni.write_value("new_setting", "value", add_if_not_found=True)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Features
|
|
67
|
+
|
|
68
|
+
- Load INI files from local filesystem or URLs
|
|
69
|
+
- Automatic type conversion (int, float, bool, str)
|
|
70
|
+
- Write values back to files
|
|
71
|
+
- Error handling with detailed messages
|
|
72
|
+
- Static class design for easy use across modules
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# QuickINI
|
|
2
|
+
|
|
3
|
+
A simple and fast INI file parser for Python with support for loading from URLs and automatic type conversion.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install quickini
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from quickini import QuickIni
|
|
15
|
+
|
|
16
|
+
# Load from file
|
|
17
|
+
QuickIni.load_file("config.ini")
|
|
18
|
+
|
|
19
|
+
# Load from URL
|
|
20
|
+
QuickIni.load_file("https://example.com/config.ini")
|
|
21
|
+
|
|
22
|
+
# Get values with automatic type conversion
|
|
23
|
+
debug = QuickIni.get_value("debug", False) # Returns boolean
|
|
24
|
+
port = QuickIni.get_value("port", 8080) # Returns integer
|
|
25
|
+
|
|
26
|
+
# Write values back to file
|
|
27
|
+
QuickIni.write_value("new_setting", "value", add_if_not_found=True)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- Load INI files from local filesystem or URLs
|
|
33
|
+
- Automatic type conversion (int, float, bool, str)
|
|
34
|
+
- Write values back to files
|
|
35
|
+
- Error handling with detailed messages
|
|
36
|
+
- Static class design for easy use across modules
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools", "wheel"]
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
from .quick_ini import QuickIni
|
|
1
|
+
from .quick_ini import QuickIni
|
|
@@ -1,229 +1,230 @@
|
|
|
1
|
-
from urllib.parse import urlparse
|
|
2
|
-
from typing import Type, Any
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
class QuickIni:
|
|
6
|
-
parsed_ini:
|
|
7
|
-
loaded_file_path:str=None
|
|
8
|
-
auto_type_convert_g:bool=True
|
|
9
|
-
error_message:str = ""
|
|
10
|
-
web_file:str = None
|
|
11
|
-
|
|
12
|
-
@staticmethod
|
|
13
|
-
def grab_from_url(url:str) -> bool:
|
|
14
|
-
import urllib.request, urllib.error
|
|
15
|
-
try:
|
|
16
|
-
with urllib.request.urlopen(url) as response:
|
|
17
|
-
if(response.status == 200):
|
|
18
|
-
QuickIni.web_file = response.read().decode('utf-8')
|
|
19
|
-
return True
|
|
20
|
-
else:
|
|
21
|
-
QuickIni.error_message = f"Failed to download file from {url}, got response: {response.status}"
|
|
22
|
-
return False
|
|
23
|
-
except urllib.error.HTTPError as e:
|
|
24
|
-
QuickIni.error_message = f"Could not get file from URL: '{e}'"
|
|
25
|
-
return False
|
|
26
|
-
|
|
27
|
-
@staticmethod
|
|
28
|
-
def is_string_url(stri:str) -> bool:
|
|
29
|
-
try:
|
|
30
|
-
res = urlparse(stri)
|
|
31
|
-
return all([res.scheme, res.netloc])
|
|
32
|
-
except ValueError:
|
|
33
|
-
return False
|
|
34
|
-
|
|
35
|
-
@staticmethod
|
|
36
|
-
def get_last_error() -> str:
|
|
37
|
-
"""
|
|
38
|
-
Returns the last error thrown by the library
|
|
39
|
-
Returns:
|
|
40
|
-
str: A formatted error message
|
|
41
|
-
"""
|
|
42
|
-
return QuickIni.error_message
|
|
43
|
-
|
|
44
|
-
@staticmethod
|
|
45
|
-
def string_to_type(s:str) -> Any:
|
|
46
|
-
"""
|
|
47
|
-
Convert a string to the appropriate type (int, float, bool, or str).
|
|
48
|
-
|
|
49
|
-
Parameters:
|
|
50
|
-
s (str): The input string to convert.
|
|
51
|
-
|
|
52
|
-
Returns:
|
|
53
|
-
Any: The converted value as int, float, bool, or str, based on the content of `s`.
|
|
54
|
-
- Returns an int if `s` contains only digits.
|
|
55
|
-
- Returns a float if `s` is a numeric value with a single decimal point.
|
|
56
|
-
- Returns a boolean (True or False) if `s` matches the strings "true" or "false" (case-insensitive).
|
|
57
|
-
- Returns `s` unchanged if no other conditions are met.
|
|
58
|
-
"""
|
|
59
|
-
if(s.isnumeric()): return int(s)
|
|
60
|
-
elif(s.count(".") == 1 and s.replace(".", "").isnumeric()): return float(s)
|
|
61
|
-
elif(s.lower() == "false"): return False
|
|
62
|
-
elif(s.lower() == "true"): return True
|
|
63
|
-
return s
|
|
64
|
-
|
|
65
|
-
@staticmethod
|
|
66
|
-
def load_file(file_location:str, auto_type_convert:bool = True, empty_default:Any = None) -> bool:
|
|
67
|
-
"""
|
|
68
|
-
Load a ini style file from the file system or from a URL.
|
|
69
|
-
\nUse get_value() or get_all() to access.
|
|
70
|
-
Args:
|
|
71
|
-
name (str): The path/URL of the file to load.
|
|
72
|
-
auto_type_convert (bool): Automaticly convert into recognized types such as True/False, int, float.
|
|
73
|
-
empty_default (Any): The default value when a value is left blank (overrides auto_type_convert).
|
|
74
|
-
Returns:
|
|
75
|
-
bool: True if successfull, False otherwise
|
|
76
|
-
Example:
|
|
77
|
-
>>> load_file("../config.ini", empty_default="")
|
|
78
|
-
True
|
|
79
|
-
"""
|
|
80
|
-
QuickIni.parsed_ini = {}
|
|
81
|
-
QuickIni.auto_type_convert_g = auto_type_convert
|
|
82
|
-
|
|
83
|
-
f_data:str = None
|
|
84
|
-
|
|
85
|
-
# Check if the provided location is a URL
|
|
86
|
-
if(QuickIni.is_string_url(file_location)):
|
|
87
|
-
if(not QuickIni.grab_from_url(file_location)):
|
|
88
|
-
# The grab_from_url sets the error message
|
|
89
|
-
return False
|
|
90
|
-
f_data = QuickIni.web_file
|
|
91
|
-
# Otherwise assume it's a file path
|
|
92
|
-
else:
|
|
93
|
-
try:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
42
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
file.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
backup_file.
|
|
183
|
-
backup_file.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
1
|
+
from urllib.parse import urlparse
|
|
2
|
+
from typing import Type, Any, Union, Dict, Optional
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
class QuickIni:
|
|
6
|
+
parsed_ini: Dict[str, Union[str, int, bool, float, None]] = {}
|
|
7
|
+
loaded_file_path: Optional[str] = None
|
|
8
|
+
auto_type_convert_g: bool = True
|
|
9
|
+
error_message: str = ""
|
|
10
|
+
web_file: Optional[str] = None
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def grab_from_url(url:str) -> bool:
|
|
14
|
+
import urllib.request, urllib.error
|
|
15
|
+
try:
|
|
16
|
+
with urllib.request.urlopen(url) as response:
|
|
17
|
+
if(response.status == 200):
|
|
18
|
+
QuickIni.web_file = response.read().decode('utf-8')
|
|
19
|
+
return True
|
|
20
|
+
else:
|
|
21
|
+
QuickIni.error_message = f"Failed to download file from {url}, got response: {response.status}"
|
|
22
|
+
return False
|
|
23
|
+
except urllib.error.HTTPError as e:
|
|
24
|
+
QuickIni.error_message = f"Could not get file from URL: '{e}'"
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def is_string_url(stri:str) -> bool:
|
|
29
|
+
try:
|
|
30
|
+
res = urlparse(stri)
|
|
31
|
+
return all([res.scheme, res.netloc])
|
|
32
|
+
except ValueError:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def get_last_error() -> str:
|
|
37
|
+
"""
|
|
38
|
+
Returns the last error thrown by the library
|
|
39
|
+
Returns:
|
|
40
|
+
str: A formatted error message
|
|
41
|
+
"""
|
|
42
|
+
return QuickIni.error_message
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def string_to_type(s:str) -> Any:
|
|
46
|
+
"""
|
|
47
|
+
Convert a string to the appropriate type (int, float, bool, or str).
|
|
48
|
+
|
|
49
|
+
Parameters:
|
|
50
|
+
s (str): The input string to convert.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Any: The converted value as int, float, bool, or str, based on the content of `s`.
|
|
54
|
+
- Returns an int if `s` contains only digits.
|
|
55
|
+
- Returns a float if `s` is a numeric value with a single decimal point.
|
|
56
|
+
- Returns a boolean (True or False) if `s` matches the strings "true" or "false" (case-insensitive).
|
|
57
|
+
- Returns `s` unchanged if no other conditions are met.
|
|
58
|
+
"""
|
|
59
|
+
if(s.isnumeric()): return int(s)
|
|
60
|
+
elif(s.count(".") == 1 and s.replace(".", "").isnumeric()): return float(s)
|
|
61
|
+
elif(s.lower() == "false"): return False
|
|
62
|
+
elif(s.lower() == "true"): return True
|
|
63
|
+
return s
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def load_file(file_location:str, auto_type_convert:bool = True, empty_default:Any = None) -> bool:
|
|
67
|
+
"""
|
|
68
|
+
Load a ini style file from the file system or from a URL.
|
|
69
|
+
\nUse get_value() or get_all() to access.
|
|
70
|
+
Args:
|
|
71
|
+
name (str): The path/URL of the file to load.
|
|
72
|
+
auto_type_convert (bool): Automaticly convert into recognized types such as True/False, int, float.
|
|
73
|
+
empty_default (Any): The default value when a value is left blank (overrides auto_type_convert).
|
|
74
|
+
Returns:
|
|
75
|
+
bool: True if successfull, False otherwise
|
|
76
|
+
Example:
|
|
77
|
+
>>> load_file("../config.ini", empty_default="")
|
|
78
|
+
True
|
|
79
|
+
"""
|
|
80
|
+
QuickIni.parsed_ini = {}
|
|
81
|
+
QuickIni.auto_type_convert_g = auto_type_convert
|
|
82
|
+
|
|
83
|
+
f_data:str = None
|
|
84
|
+
|
|
85
|
+
# Check if the provided location is a URL
|
|
86
|
+
if(QuickIni.is_string_url(file_location)):
|
|
87
|
+
if(not QuickIni.grab_from_url(file_location)):
|
|
88
|
+
# The grab_from_url sets the error message
|
|
89
|
+
return False
|
|
90
|
+
f_data = QuickIni.web_file
|
|
91
|
+
# Otherwise assume it's a file path
|
|
92
|
+
else:
|
|
93
|
+
try:
|
|
94
|
+
with open(str(file_location), 'r', encoding='utf-8') as file:
|
|
95
|
+
f_data = file.read()
|
|
96
|
+
except FileNotFoundError:
|
|
97
|
+
QuickIni.error_message = f"Could not find file at: '{file_location}'"
|
|
98
|
+
return False
|
|
99
|
+
except IOError as e:
|
|
100
|
+
QuickIni.error_message = f"Error reading file: '{e}'"
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
lines = f_data.splitlines()
|
|
104
|
+
|
|
105
|
+
for line in lines:
|
|
106
|
+
if(line.startswith("#") or "=" not in line): continue # Ignore comments and lines without "="
|
|
107
|
+
left, right = line.split("=", 1)
|
|
108
|
+
if(not right): right = empty_default
|
|
109
|
+
elif(not auto_type_convert): pass # If we aren't auto converting, skip the conversion
|
|
110
|
+
else: right = QuickIni.string_to_type(right)
|
|
111
|
+
|
|
112
|
+
QuickIni.parsed_ini[left] = right
|
|
113
|
+
|
|
114
|
+
QuickIni.loaded_file_path=file_location
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def get_value(name:str, default:Any = None, expected_type:Type = None) -> Any:
|
|
119
|
+
"""
|
|
120
|
+
Returns the value attached to the given name.
|
|
121
|
+
\nIf no setting is found, it will return the passed in default
|
|
122
|
+
Args:
|
|
123
|
+
name (str): The name of the setting
|
|
124
|
+
default (Any): What will be returned if nothing is found
|
|
125
|
+
expected_type (Type): Will make sure the returned object is of this Type, otherwise Raise()
|
|
126
|
+
Return:
|
|
127
|
+
Any: The value associated with the name
|
|
128
|
+
Example:
|
|
129
|
+
>>> get_value("do_debug_logs", False)
|
|
130
|
+
True
|
|
131
|
+
"""
|
|
132
|
+
value:Any = QuickIni.parsed_ini.get(name, default)
|
|
133
|
+
if(expected_type != None):
|
|
134
|
+
if(not isinstance(value, expected_type)):
|
|
135
|
+
QuickIni.error_message = f"Expected type '{expected_type.__name__}', instead got '{type(value).__name__}'"
|
|
136
|
+
raise(ValueError(QuickIni.error_message))
|
|
137
|
+
return value
|
|
138
|
+
|
|
139
|
+
def write_value(key:str, value:Any, add_if_not_found:bool=False, update_locally:bool=True, do_backup:bool=False) -> Any:
|
|
140
|
+
"""
|
|
141
|
+
Writes a key-value pair to the loaded .ini file, with an optional dry run mode.
|
|
142
|
+
|
|
143
|
+
Parameters:
|
|
144
|
+
key (str): The key to update or add in the .ini file.
|
|
145
|
+
value (Any): The value to write, which will be converted to a string.
|
|
146
|
+
add_if_not_found (bool): If True, adds the key-value pair if the key is not found in the file (default is False).
|
|
147
|
+
update_localy (bool): If True, updates the parsed_ini dictionary locally with the new key-value pair (default is True).
|
|
148
|
+
do_backup (bool): If True, creates a backup of the original file before making changes, and removes if successful.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Any: The value written or simulated, with optional type conversion if `auto_type_convert` was enabled.
|
|
152
|
+
|
|
153
|
+
Raises:
|
|
154
|
+
ValueError: If no file path is loaded or if the value cannot be converted to a string.
|
|
155
|
+
FileNotFoundError: If the specified file cannot be found.
|
|
156
|
+
PermissionError: If there is an issue with file permissions.
|
|
157
|
+
IOError: If there is a read or write error.
|
|
158
|
+
|
|
159
|
+
Example:
|
|
160
|
+
>>> write_value("example_key", 42, add_if_not_found=True)
|
|
161
|
+
42
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
if(not QuickIni.loaded_file_path):
|
|
165
|
+
QuickIni.error_message = "No loaded file path, was a local file loaded?"
|
|
166
|
+
raise(ValueError(QuickIni.error_message))
|
|
167
|
+
|
|
168
|
+
try: str(value)
|
|
169
|
+
except(TypeError, ValueError):
|
|
170
|
+
QuickIni.error_message = "Could not convert value to a string"
|
|
171
|
+
raise(ValueError(QuickIni.error_message))
|
|
172
|
+
|
|
173
|
+
key_value_pair = f"{str(key)}={str(value)}\n"
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
file = open(str(QuickIni.loaded_file_path), 'r', encoding='utf-8')
|
|
177
|
+
lines = file.readlines()
|
|
178
|
+
file.close()
|
|
179
|
+
|
|
180
|
+
# Create backup
|
|
181
|
+
if(do_backup):
|
|
182
|
+
backup_file = open(f"{str(QuickIni.loaded_file_path)}.backup", 'w', encoding='utf-8')
|
|
183
|
+
backup_file.writelines(lines)
|
|
184
|
+
backup_file.close()
|
|
185
|
+
print("Backup created at", f"{str(QuickIni.loaded_file_path)}.backup")
|
|
186
|
+
|
|
187
|
+
key_found=False
|
|
188
|
+
last_line=""
|
|
189
|
+
file = open(str(QuickIni.loaded_file_path), 'w')
|
|
190
|
+
for line in lines:
|
|
191
|
+
if(not line.startswith("#") and not key_found and line.startswith(f"{key}=")):
|
|
192
|
+
last_line = key_value_pair
|
|
193
|
+
key_found = True
|
|
194
|
+
else:
|
|
195
|
+
last_line = line
|
|
196
|
+
file.write(last_line)
|
|
197
|
+
|
|
198
|
+
if(not key_found):
|
|
199
|
+
if(add_if_not_found):
|
|
200
|
+
if(not last_line.endswith("\n")):
|
|
201
|
+
file.write("\n")
|
|
202
|
+
file.write(f"{key_value_pair}")
|
|
203
|
+
else:
|
|
204
|
+
QuickIni.error_message = f"Could not find key '{key}'"
|
|
205
|
+
raise(ValueError(QuickIni.error_message))
|
|
206
|
+
|
|
207
|
+
file.close()
|
|
208
|
+
|
|
209
|
+
except FileNotFoundError as e:
|
|
210
|
+
QuickIni.error_message = f"Could not find file '{QuickIni.loaded_file_path}'"
|
|
211
|
+
raise(e)
|
|
212
|
+
except PermissionError as e:
|
|
213
|
+
QuickIni.error_message = f"Permission error for file '{QuickIni.loaded_file_path}'"
|
|
214
|
+
raise(e)
|
|
215
|
+
except IOError as e:
|
|
216
|
+
QuickIni.error_message = f"IOError when reading or writting to the file '{QuickIni.loaded_file_path}'"
|
|
217
|
+
raise(e)
|
|
218
|
+
|
|
219
|
+
v = QuickIni.string_to_type(str(value)) if QuickIni.auto_type_convert_g else str(value)
|
|
220
|
+
if(update_locally):
|
|
221
|
+
QuickIni.parsed_ini[str(key)] = v
|
|
222
|
+
|
|
223
|
+
# Remove backup
|
|
224
|
+
if(do_backup):
|
|
225
|
+
try: os.remove(f"{str(QuickIni.loaded_file_path)}.backup")
|
|
226
|
+
except Exception as e:
|
|
227
|
+
QuickIni.error_message = "Failed to remove backup file"
|
|
228
|
+
raise(e)
|
|
229
|
+
|
|
230
|
+
return v
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quick_ini
|
|
3
|
+
Version: 3.1.4
|
|
4
|
+
Summary: A library for reading from and writing to .ini formatted files
|
|
5
|
+
Home-page: https://github.com/olliez-mods/Quick-Ini
|
|
6
|
+
Author: OllieZ-Mods
|
|
7
|
+
Author-email: socksinthewash@gmail.com
|
|
8
|
+
Project-URL: Bug Reports, https://github.com/olliez-mods/Quick-Ini/issues
|
|
9
|
+
Project-URL: Source, https://github.com/olliez-mods/Quick-Ini
|
|
10
|
+
Keywords: ini config configuration parser file
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Requires-Python: >=3.7
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: keywords
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
Dynamic: project-url
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
Dynamic: summary
|
|
36
|
+
|
|
37
|
+
# QuickINI
|
|
38
|
+
|
|
39
|
+
A simple and fast INI file parser for Python with support for loading from URLs and automatic type conversion.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install quickini
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from quickini import QuickIni
|
|
51
|
+
|
|
52
|
+
# Load from file
|
|
53
|
+
QuickIni.load_file("config.ini")
|
|
54
|
+
|
|
55
|
+
# Load from URL
|
|
56
|
+
QuickIni.load_file("https://example.com/config.ini")
|
|
57
|
+
|
|
58
|
+
# Get values with automatic type conversion
|
|
59
|
+
debug = QuickIni.get_value("debug", False) # Returns boolean
|
|
60
|
+
port = QuickIni.get_value("port", 8080) # Returns integer
|
|
61
|
+
|
|
62
|
+
# Write values back to file
|
|
63
|
+
QuickIni.write_value("new_setting", "value", add_if_not_found=True)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Features
|
|
67
|
+
|
|
68
|
+
- Load INI files from local filesystem or URLs
|
|
69
|
+
- Automatic type conversion (int, float, bool, str)
|
|
70
|
+
- Write values back to files
|
|
71
|
+
- Error handling with detailed messages
|
|
72
|
+
- Static class design for easy use across modules
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
LICENSE
|
|
1
2
|
README.md
|
|
2
3
|
pyproject.toml
|
|
3
4
|
setup.py
|
|
@@ -6,4 +7,6 @@ quick_ini/quick_ini.py
|
|
|
6
7
|
quick_ini.egg-info/PKG-INFO
|
|
7
8
|
quick_ini.egg-info/SOURCES.txt
|
|
8
9
|
quick_ini.egg-info/dependency_links.txt
|
|
9
|
-
quick_ini.egg-info/top_level.txt
|
|
10
|
+
quick_ini.egg-info/top_level.txt
|
|
11
|
+
tests/__init__.py
|
|
12
|
+
tests/test_quickini.py
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[egg_info]
|
|
2
|
-
tag_build =
|
|
3
|
-
tag_date = 0
|
|
4
|
-
|
|
1
|
+
[egg_info]
|
|
2
|
+
tag_build =
|
|
3
|
+
tag_date = 0
|
|
4
|
+
|
quick_ini-3.1.4/setup.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="quick_ini",
|
|
8
|
+
version="3.1.4",
|
|
9
|
+
description="A library for reading from and writing to .ini formatted files",
|
|
10
|
+
long_description=long_description,
|
|
11
|
+
long_description_content_type="text/markdown",
|
|
12
|
+
author="OllieZ-Mods",
|
|
13
|
+
author_email="socksinthewash@gmail.com",
|
|
14
|
+
url="https://github.com/olliez-mods/Quick-Ini",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.7",
|
|
23
|
+
"Programming Language :: Python :: 3.8",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
],
|
|
29
|
+
python_requires=">=3.7",
|
|
30
|
+
keywords="ini config configuration parser file",
|
|
31
|
+
project_urls={
|
|
32
|
+
"Bug Reports": "https://github.com/olliez-mods/Quick-Ini/issues",
|
|
33
|
+
"Source": "https://github.com/olliez-mods/Quick-Ini",
|
|
34
|
+
},
|
|
35
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests package
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import tempfile
|
|
3
|
+
import os
|
|
4
|
+
from quick_ini import QuickIni
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestQuickIni(unittest.TestCase):
|
|
8
|
+
|
|
9
|
+
def setUp(self):
|
|
10
|
+
"""Set up test fixtures before each test method."""
|
|
11
|
+
# Create a temporary INI file for testing
|
|
12
|
+
self.test_content = """# Test configuration
|
|
13
|
+
debug=true
|
|
14
|
+
port=8080
|
|
15
|
+
timeout=30.5
|
|
16
|
+
name=TestApp
|
|
17
|
+
empty_value=
|
|
18
|
+
|
|
19
|
+
# Array example
|
|
20
|
+
parts=
|
|
21
|
+
|one
|
|
22
|
+
|two
|
|
23
|
+
|three
|
|
24
|
+
"""
|
|
25
|
+
self.temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.ini', delete=False)
|
|
26
|
+
self.temp_file.write(self.test_content)
|
|
27
|
+
self.temp_file.close()
|
|
28
|
+
|
|
29
|
+
def tearDown(self):
|
|
30
|
+
"""Clean up after each test method."""
|
|
31
|
+
if os.path.exists(self.temp_file.name):
|
|
32
|
+
os.unlink(self.temp_file.name)
|
|
33
|
+
|
|
34
|
+
def test_load_file(self):
|
|
35
|
+
"""Test loading an INI file."""
|
|
36
|
+
result = QuickIni.load_file(self.temp_file.name)
|
|
37
|
+
self.assertTrue(result)
|
|
38
|
+
|
|
39
|
+
def test_get_value_string(self):
|
|
40
|
+
"""Test getting string values."""
|
|
41
|
+
QuickIni.load_file(self.temp_file.name)
|
|
42
|
+
value = QuickIni.get_value("name")
|
|
43
|
+
self.assertEqual(value, "TestApp")
|
|
44
|
+
|
|
45
|
+
def test_get_value_boolean(self):
|
|
46
|
+
"""Test getting boolean values."""
|
|
47
|
+
QuickIni.load_file(self.temp_file.name)
|
|
48
|
+
value = QuickIni.get_value("debug")
|
|
49
|
+
self.assertTrue(value)
|
|
50
|
+
self.assertIsInstance(value, bool)
|
|
51
|
+
|
|
52
|
+
def test_get_value_integer(self):
|
|
53
|
+
"""Test getting integer values."""
|
|
54
|
+
QuickIni.load_file(self.temp_file.name)
|
|
55
|
+
value = QuickIni.get_value("port")
|
|
56
|
+
self.assertEqual(value, 8080)
|
|
57
|
+
self.assertIsInstance(value, int)
|
|
58
|
+
|
|
59
|
+
def test_get_value_float(self):
|
|
60
|
+
"""Test getting float values."""
|
|
61
|
+
QuickIni.load_file(self.temp_file.name)
|
|
62
|
+
value = QuickIni.get_value("timeout")
|
|
63
|
+
self.assertEqual(value, 30.5)
|
|
64
|
+
self.assertIsInstance(value, float)
|
|
65
|
+
|
|
66
|
+
def test_get_value_default(self):
|
|
67
|
+
"""Test getting default values for missing keys."""
|
|
68
|
+
QuickIni.load_file(self.temp_file.name)
|
|
69
|
+
value = QuickIni.get_value("missing_key", "default")
|
|
70
|
+
self.assertEqual(value, "default")
|
|
71
|
+
|
|
72
|
+
def test_write_value(self):
|
|
73
|
+
"""Test writing values to file."""
|
|
74
|
+
QuickIni.load_file(self.temp_file.name)
|
|
75
|
+
result = QuickIni.write_value("new_key", "new_value", add_if_not_found=True)
|
|
76
|
+
self.assertEqual(result, "new_value")
|
|
77
|
+
|
|
78
|
+
# Verify it was written
|
|
79
|
+
value = QuickIni.get_value("new_key")
|
|
80
|
+
self.assertEqual(value, "new_value")
|
|
81
|
+
|
|
82
|
+
def test_error_handling(self):
|
|
83
|
+
"""Test error handling for missing files."""
|
|
84
|
+
result = QuickIni.load_file("nonexistent_file.ini")
|
|
85
|
+
self.assertFalse(result)
|
|
86
|
+
error = QuickIni.get_last_error()
|
|
87
|
+
self.assertIn("Could not find file", error)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == '__main__':
|
|
91
|
+
unittest.main()
|
quick_ini-3.0/PKG-INFO
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: quick_ini
|
|
3
|
-
Version: 3.0
|
|
4
|
-
Summary: A library for reading from and writting to .ini formatted files
|
|
5
|
-
Home-page: https://github.com/olliez-mods/Quick-Ini
|
|
6
|
-
Author: OllieZ-Mods
|
|
7
|
-
Author-email: socksinthewash@gmail.com
|
|
8
|
-
Description-Content-Type: text/markdown
|
quick_ini-3.0/README.md
DELETED
|
File without changes
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: quick_ini
|
|
3
|
-
Version: 3.0
|
|
4
|
-
Summary: A library for reading from and writting to .ini formatted files
|
|
5
|
-
Home-page: https://github.com/olliez-mods/Quick-Ini
|
|
6
|
-
Author: OllieZ-Mods
|
|
7
|
-
Author-email: socksinthewash@gmail.com
|
|
8
|
-
Description-Content-Type: text/markdown
|
quick_ini-3.0/setup.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from setuptools import setup, find_packages
|
|
2
|
-
|
|
3
|
-
setup(
|
|
4
|
-
name="quick_ini",
|
|
5
|
-
version="3.0",
|
|
6
|
-
description="A library for reading from and writting to .ini formatted files",
|
|
7
|
-
long_description=open('README.md').read(),
|
|
8
|
-
long_description_content_type="text/markdown",
|
|
9
|
-
author="OllieZ-Mods",
|
|
10
|
-
author_email="socksinthewash@gmail.com",
|
|
11
|
-
url="https://github.com/olliez-mods/Quick-Ini",
|
|
12
|
-
packages=find_packages()
|
|
13
|
-
)
|
|
File without changes
|