pyquoks 1.2.2__py3-none-any.whl → 1.3.0__py3-none-any.whl

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.
pyquoks/data.py CHANGED
@@ -1,211 +1,522 @@
1
1
  from __future__ import annotations
2
- import configparser, datetime, logging, json, sys, io, os
2
+ import configparser, datetime, logging, sqlite3, json, sys, io, os
3
3
  import requests, PIL.Image, PIL.ImageDraw
4
4
  from . import utils
5
5
 
6
6
 
7
- # Providers
7
+ # region Providers
8
+
8
9
  class IDataProvider:
9
- _PATH: str
10
+ """
11
+ Class for providing data from JSON-like files
12
+ """
13
+
14
+ _PATH: str = utils.get_path("data/")
15
+ """
16
+ Path to the directory with JSON-like files
17
+ """
18
+
19
+ _FILENAME: str = "{0}.json"
20
+ """
21
+ Filename of JSON-like files
22
+ """
23
+
10
24
  _DATA_VALUES: dict[str, type]
25
+ """
26
+ Dictionary with filenames and containers
27
+
28
+ Example:
29
+ _DATA_VALUES = {"users": UsersContainer}
30
+ """
11
31
 
12
32
  def __init__(self) -> None:
13
- for k, v in self._DATA_VALUES.items():
33
+ for filename, container in self._DATA_VALUES.items():
14
34
  try:
15
- with open(self._PATH.format(k), "rb") as file:
16
- setattr(self, k, v(json_data=json.loads(file.read())))
35
+ with open(self._PATH + self._FILENAME.format(filename), "rb") as file:
36
+ setattr(self, filename, container(json.loads(file.read())))
17
37
  except:
18
- setattr(self, k, None)
38
+ setattr(self, filename, None)
19
39
 
20
40
 
21
41
  class IConfigProvider:
42
+ """
43
+ Class for providing data from configuration file
44
+ """
45
+
22
46
  class IConfig:
47
+ """
48
+ Class that represents a section in configuration file
49
+ """
50
+
23
51
  _SECTION: str = None
52
+ """
53
+ Name of the section in configuration file
54
+
55
+ Example:
56
+ _SECTION = "Settings"
57
+ """
58
+
24
59
  _CONFIG_VALUES: dict[str, type]
60
+ """
61
+ Dictionary with settings and their types
62
+ """
25
63
 
26
64
  def __init__(self, parent: IConfigProvider = None) -> None:
27
65
  if isinstance(parent, IConfigProvider):
28
66
  self._CONFIG_VALUES = parent._CONFIG_VALUES.get(self._SECTION)
29
- self._incorrect_content_exception = configparser.ParsingError("config.ini is filled incorrectly!")
67
+
68
+ self._incorrect_content_exception = configparser.ParsingError(
69
+ "configuration file is filled incorrectly!"
70
+ )
30
71
  self._config = configparser.ConfigParser()
31
- self._config.read(utils.get_path("config.ini"))
72
+ self._config.read(parent._PATH)
73
+
32
74
  if not self._config.has_section(self._SECTION):
33
75
  self._config.add_section(self._SECTION)
34
- for k, v in self._CONFIG_VALUES.items():
76
+
77
+ for setting, data_type in self._CONFIG_VALUES.items():
35
78
  try:
36
- setattr(self, k, self._config.get(self._SECTION, k))
79
+ setattr(self, setting, self._config.get(self._SECTION, setting))
37
80
  except:
38
- self._config.set(self._SECTION, k, v.__name__)
39
- with open(utils.get_path("config.ini"), "w", encoding="utf-8") as file:
40
- self._config.write(fp=file)
41
- for k, v in self._CONFIG_VALUES.items():
81
+ self._config.set(self._SECTION, setting, data_type.__name__)
82
+ with open(parent._PATH, "w", encoding="utf-8") as file:
83
+ self._config.write(file)
84
+
85
+ for setting, data_type in self._CONFIG_VALUES.items():
42
86
  try:
43
- if v == int:
44
- setattr(self, k, int(getattr(self, k)))
45
- elif v == bool:
46
- if getattr(self, k) not in (str(True), str(False)):
47
- setattr(self, k, None)
48
- raise self._incorrect_content_exception
49
- else:
50
- setattr(self, k, getattr(self, k) == str(True))
51
- elif v in (dict, list):
52
- setattr(self, k, json.loads(getattr(self, k)))
87
+ match data_type.__name__:
88
+ case "int":
89
+ setattr(self, setting, int(getattr(self, setting)))
90
+ case "bool":
91
+ if getattr(self, setting) not in (str(True), str(False)):
92
+ setattr(self, setting, None)
93
+ raise self._incorrect_content_exception
94
+ else:
95
+ setattr(self, setting, getattr(self, setting) == str(True))
96
+ case "dict" | "list":
97
+ setattr(self, setting, json.loads(getattr(self, setting)))
53
98
  except:
54
- setattr(self, k, None)
99
+ setattr(self, setting, None)
55
100
  raise self._incorrect_content_exception
101
+
56
102
  if not self.values:
57
103
  raise self._incorrect_content_exception
58
104
 
59
105
  @property
60
106
  def values(self) -> dict | None:
107
+ """
108
+ :return: Values stored in section
109
+ """
110
+
61
111
  try:
62
- return {i: getattr(self, i) for i in self._CONFIG_VALUES}
112
+ return {setting: getattr(self, setting) for setting in self._CONFIG_VALUES.keys()}
63
113
  except:
64
114
  return None
65
115
 
116
+ _PATH: str = utils.get_path("config.ini")
117
+ """
118
+ Path to the configuration file
119
+ """
120
+
66
121
  _CONFIG_VALUES: dict[str, dict[str, type]]
122
+ """
123
+ Dictionary with sections, their settings and their types
124
+
125
+ Example:
126
+ _CONFIG_VALUES = {"Settings": {"version": str}}
127
+ """
128
+
67
129
  _CONFIG_OBJECTS: dict[str, type]
130
+ """
131
+ Dictionary with names of attributes and child objects
132
+
133
+ Example:
134
+ _CONFIG_OBJECTS = {"settings": SettingsConfig}
135
+ """
68
136
 
69
137
  def __init__(self) -> None:
70
- for k, v in self._CONFIG_OBJECTS.items():
71
- setattr(self, k, v(self))
138
+ for name, data_class in self._CONFIG_OBJECTS.items():
139
+ setattr(self, name, data_class(self))
72
140
 
73
141
 
74
142
  class IAssetsProvider:
143
+ """
144
+ Class for providing various assets data
145
+ """
146
+
75
147
  class IDirectory:
148
+ """
149
+ Class that represents a directory with various assets
150
+ """
151
+
76
152
  _PATH: str = None
153
+ """
154
+ Path to the directory with assets files
155
+
156
+ Example:
157
+ _PATH = "images/"
158
+ """
159
+
160
+ _FILENAME: str = None
161
+ """
162
+ Filename of assets files
163
+
164
+ Example:
165
+ _FILENAME = "{0}.png"
166
+ """
167
+
77
168
  _NAMES: set[str]
169
+ """
170
+ Names of files in the directory
171
+
172
+ Example:
173
+ _NAMES = {"picture1", "picture2"}
174
+ """
78
175
 
79
176
  def __init__(self, parent: IAssetsProvider) -> None:
80
- for i in self._NAMES:
81
- setattr(self, i, parent.file_image(parent._PATH.format(self._PATH.format(i))))
177
+ self._PATH = parent._PATH + self._PATH
178
+
179
+ if isinstance(parent, IAssetsProvider):
180
+ for filename in self._NAMES:
181
+ setattr(self, filename, parent.file_image(self._PATH + self._FILENAME.format(filename)))
82
182
 
83
183
  class INetwork:
184
+ """
185
+ Class that represents a set of images obtained from a network
186
+ """
187
+
84
188
  _URLS: dict[str, str]
189
+ """
190
+ Dictionary with names of attributes and URLs
191
+
192
+ Example:
193
+ _URLS = {"example": "https://example.com/image.png"}
194
+ """
85
195
 
86
196
  def __init__(self, parent: IAssetsProvider) -> None:
87
- for k, v in self._URLS:
88
- setattr(self, k, parent.network_image(v))
197
+ if isinstance(parent, IAssetsProvider):
198
+ for name, url in self._URLS.items():
199
+ setattr(self, name, parent.network_image(url))
200
+
201
+ _PATH: str = utils.get_path("assets/")
202
+ """
203
+ Path to the directory with assets folders
204
+ """
89
205
 
90
- _PATH: str
91
206
  _ASSETS_OBJECTS: dict[str, type]
207
+ """
208
+ Dictionary with names of attributes and child objects
209
+
210
+ Example:
211
+ _ASSETS_OBJECTS = {"images": ImagesAssets, "example": ExampleNetwork}
212
+ """
92
213
 
93
214
  def __init__(self) -> None:
94
- for k, v in self._ASSETS_OBJECTS.items():
95
- setattr(self, k, v(self))
215
+ for name, data_class in self._ASSETS_OBJECTS.items():
216
+ setattr(self, name, data_class(self))
96
217
 
97
218
  @staticmethod
98
219
  def file_image(path: str) -> PIL.Image.Image:
220
+ """
221
+ :return: Image object from a file
222
+ """
223
+
99
224
  with open(path, "rb") as file:
100
225
  return PIL.Image.open(io.BytesIO(file.read()))
101
226
 
102
227
  @staticmethod
103
228
  def network_image(url: str) -> PIL.Image.Image:
229
+ """
230
+ :return: Image object from a URL
231
+ """
232
+
104
233
  return PIL.Image.open(io.BytesIO(requests.get(url).content))
105
234
 
106
235
  @staticmethod
107
236
  def round_corners(image: PIL.Image.Image, radius: int) -> PIL.Image.Image:
237
+ """
238
+ :return: Image with rounded edges of the specified radius
239
+ """
240
+
108
241
  if image.mode != "RGB":
109
242
  image = image.convert("RGB")
110
243
  width, height = image.size
244
+
111
245
  shape = PIL.Image.new("L", (radius * 2, radius * 2), 0)
112
- alpha = PIL.Image.new("L", image.size, "white")
113
246
  PIL.ImageDraw.Draw(shape).ellipse((0, 0, radius * 2, radius * 2), fill=255)
247
+
248
+ alpha = PIL.Image.new("L", image.size, "white")
114
249
  alpha.paste(shape.crop((0, 0, radius, radius)), (0, 0))
115
250
  alpha.paste(shape.crop((0, radius, radius, radius * 2)), (0, height - radius))
116
251
  alpha.paste(shape.crop((radius, 0, radius * 2, radius)), (width - radius, 0))
117
252
  alpha.paste(shape.crop((radius, radius, radius * 2, radius * 2)), (width - radius, height - radius))
118
253
  image.putalpha(alpha)
254
+
119
255
  return image
120
256
 
121
257
 
122
258
  class IStringsProvider:
259
+ """
260
+ Class for providing various strings data
261
+ """
262
+
123
263
  class IStrings:
264
+ """
265
+ Class that represents a container for strings
266
+ """
267
+
124
268
  pass
125
269
 
126
270
  _STRINGS_OBJECTS: dict[str, type]
271
+ """
272
+ Dictionary with names of attributes and child objects
273
+
274
+ Example:
275
+ _STRINGS_OBJECTS = {"localizable": LocalizableStrings}
276
+ """
277
+
278
+ def __init__(self) -> None:
279
+ for name, data_class in self._STRINGS_OBJECTS.items():
280
+ setattr(self, name, data_class())
281
+
282
+
283
+ # endregion
284
+
285
+ # region Managers
286
+
287
+ class IDatabaseManager:
288
+ """
289
+ Class for managing database connections
290
+ """
291
+
292
+ class IDatabase(sqlite3.Connection):
293
+ """
294
+ Class that represents a database connection
295
+ """
296
+
297
+ _NAME: str = None
298
+ """
299
+ Name of the database
300
+
301
+ Example:
302
+ _NAME = "users"
303
+ """
304
+
305
+ _SQL: str = None
306
+ """
307
+ SQL expression for creating a database
308
+
309
+ Example:
310
+ _SQL = f\"\"\"CREATE TABLE IF NOT EXISTS {_NAME} (user_id INTEGER PRIMARY KEY NOT NULL)\"\"\"
311
+ """
312
+
313
+ _FILENAME: str = "{0}.db"
314
+ """
315
+ File extension of database
316
+ """
317
+
318
+ def __init__(self, parent: IDatabaseManager) -> None:
319
+ if isinstance(parent, IDatabaseManager):
320
+ self._FILENAME = self._FILENAME.format(self._NAME)
321
+
322
+ super().__init__(
323
+ database=parent._PATH + self._FILENAME,
324
+ check_same_thread=False,
325
+ )
326
+
327
+ self._cursor = self.cursor()
328
+ self._db_cursor.execute(self._SQL)
329
+ self.commit()
330
+
331
+ @property
332
+ def _db_cursor(self) -> sqlite3.Cursor:
333
+ return self._cursor
334
+
335
+ _PATH: str = utils.get_path("db/")
336
+ """
337
+ Path to the directory with databases
338
+ """
339
+
340
+ _DATABASE_OBJECTS: dict[str, type]
341
+ """
342
+ Dictionary with names of attributes and child objects
343
+
344
+ Example:
345
+ _DATABASE_OBJECTS = {"users": UsersDatabase}
346
+ """
127
347
 
128
348
  def __init__(self) -> None:
129
- for k, v in self._STRINGS_OBJECTS.items():
130
- setattr(self, k, v())
349
+ os.makedirs(self._PATH, exist_ok=True)
350
+
351
+ for name, data_class in self._DATABASE_OBJECTS.items():
352
+ setattr(self, name, data_class(self))
353
+
354
+ def close_all(self) -> None:
355
+ """
356
+ Closes all database connections
357
+ """
358
+ for database in self._DATABASE_OBJECTS.keys():
359
+ getattr(self, database).close()
131
360
 
132
361
 
133
- # Managers
134
362
  if sys.platform == "win32":
135
363
  import winreg
136
364
 
137
365
 
138
366
  class IRegistryManager:
367
+ """
368
+ Class for managing data in the Windows Registry
369
+ """
370
+
139
371
  class IRegistry:
372
+ """
373
+ Class that represents a key with parameters in the Windows Registry
374
+ """
375
+
140
376
  _NAME: str = None
377
+ """
378
+ Name of key in the Windows Registry
379
+
380
+ Example:
381
+ _NAME = "OAuth"
382
+ """
383
+
141
384
  _REGISTRY_VALUES: dict[str, int]
385
+ """
386
+ Dictionary with settings and their types
387
+ """
388
+
389
+ _path: winreg.HKEYType
142
390
 
143
391
  def __init__(self, parent: IRegistryManager = None) -> None:
144
392
  if isinstance(parent, IRegistryManager):
145
393
  self._REGISTRY_VALUES = parent._REGISTRY_VALUES.get(self._NAME)
146
394
  self._path = winreg.CreateKey(parent._path, self._NAME)
147
- for i in self._REGISTRY_VALUES.keys():
395
+
396
+ for setting in self._REGISTRY_VALUES.keys():
148
397
  try:
149
- setattr(self, i, winreg.QueryValueEx(self._path, i)[int()])
398
+ setattr(self, setting, winreg.QueryValueEx(self._path, setting)[int()])
150
399
  except:
151
- setattr(self, i, None)
400
+ setattr(self, setting, None)
152
401
 
153
402
  @property
154
403
  def values(self) -> dict | None:
404
+ """
405
+ :return: Values stored in key in the Windows Registry
406
+ """
407
+
155
408
  try:
156
- return {i: getattr(self, i) for i in self._REGISTRY_VALUES}
409
+ return {setting: getattr(self, setting) for setting in self._REGISTRY_VALUES.keys()}
157
410
  except:
158
411
  return None
159
412
 
160
413
  def refresh(self) -> IRegistryManager.IRegistry:
414
+ """
415
+ :return: Instance with refreshed values
416
+ """
417
+
161
418
  self.__init__()
162
419
  return self
163
420
 
164
421
  def update(self, **kwargs) -> None:
165
- for k, v in kwargs.items():
166
- winreg.SetValueEx(self._path, k, None, self._REGISTRY_VALUES.get(k), v)
167
- setattr(self, k, v)
422
+ """
423
+ Updates provided settings in the Windows Registry
424
+ """
425
+
426
+ for setting, value in kwargs.items():
427
+ winreg.SetValueEx(self._path, setting, None, self._REGISTRY_VALUES.get(setting), value)
428
+ setattr(self, setting, value)
168
429
 
169
430
  _KEY: str
431
+ """
432
+ Path to key in the Windows Registry
433
+
434
+ Example:
435
+ _KEY = "Software\\\\\\\\diquoks Software\\\\\\\\pyquoks"
436
+ """
437
+
170
438
  _REGISTRY_VALUES: dict[str, dict[str, int]]
439
+ """
440
+ Dictionary with keys, their settings and their types
441
+
442
+ Example:
443
+ _REGISTRY_VALUES = {"OAuth": {"access_token": winreg.REG_SZ}}
444
+ """
445
+
171
446
  _REGISTRY_OBJECTS: dict[str, type]
447
+ """
448
+ Dictionary with names of attributes and child objects
449
+
450
+ Example:
451
+ _REGISTRY_OBJECTS = {"oauth": OAuthRegistry}
452
+ """
453
+
172
454
  _path: winreg.HKEYType
173
455
 
174
456
  def __init__(self) -> None:
175
457
  self._path = winreg.CreateKey(winreg.HKEY_CURRENT_USER, self._KEY)
176
- for k, v in self._REGISTRY_OBJECTS.items():
177
- setattr(self, k, v(self))
458
+
459
+ for name, data_class in self._REGISTRY_OBJECTS.items():
460
+ setattr(self, name, data_class(self))
178
461
 
179
462
  def refresh(self) -> IRegistryManager:
463
+ """
464
+ :return: Instance with refreshed values
465
+ """
466
+
180
467
  self.__init__()
181
468
  return self
182
469
 
183
470
 
184
- # Services
471
+ # endregion
472
+
473
+ # region Services
474
+
185
475
  class LoggerService(logging.Logger):
476
+ """
477
+ Class that provides methods for parallel logging
478
+ """
479
+
186
480
  def __init__(
187
481
  self,
188
482
  name: str, file_handling: bool = True,
189
483
  filename: str = datetime.datetime.now().strftime("%d-%m-%y-%H-%M-%S"),
190
484
  level: int = logging.NOTSET,
191
- folder_name: str = "logs",
485
+ path: str = utils.get_path("logs/", only_abspath=True),
192
486
  ) -> None:
193
487
  super().__init__(name, level)
488
+
194
489
  stream_handler = logging.StreamHandler(sys.stdout)
195
490
  stream_handler.setFormatter(
196
- logging.Formatter(fmt="$levelname $asctime $name - $message", datefmt="%d-%m-%y %H:%M:%S", style="$")
491
+ logging.Formatter(
492
+ fmt="$levelname $asctime $name - $message",
493
+ datefmt="%d-%m-%y %H:%M:%S",
494
+ style="$",
495
+ )
197
496
  )
198
497
  self.addHandler(stream_handler)
498
+
199
499
  if file_handling:
200
- os.makedirs(utils.get_path(folder_name, only_abspath=True), exist_ok=True)
500
+ os.makedirs(path, exist_ok=True)
501
+
201
502
  file_handler = logging.FileHandler(
202
- utils.get_path(f"{folder_name}/{filename}-{name}.log", only_abspath=True),
503
+ path + f"{filename}-{name}.log",
203
504
  encoding="utf-8",
204
505
  )
205
506
  file_handler.setFormatter(
206
- logging.Formatter(fmt="$levelname $asctime - $message", datefmt="%d-%m-%y %H:%M:%S", style="$"),
507
+ logging.Formatter(
508
+ fmt="$levelname $asctime - $message",
509
+ datefmt="%d-%m-%y %H:%M:%S",
510
+ style="$",
511
+ ),
207
512
  )
208
513
  self.addHandler(file_handler)
209
514
 
210
515
  def log_exception(self, e: Exception) -> None:
516
+ """
517
+ Logs an exception with detailed traceback
518
+ """
519
+
211
520
  self.error(msg=e, exc_info=True)
521
+
522
+ # endregion
pyquoks/localhost.py CHANGED
@@ -1,17 +1,35 @@
1
1
  from __future__ import annotations
2
- import waitress, typing, flask
2
+ import typing
3
+ import waitress, flask
3
4
 
4
5
 
5
6
  class ILocalhostFlask(flask.Flask):
7
+ """
8
+ Class for creating a simple localhost server
9
+ """
10
+
6
11
  _RULES: dict[str, typing.Callable]
12
+ """
13
+ Dictionary with rules and functions
14
+
15
+ Example:
16
+ _RULES = {"/": base_redirect}
17
+ """
7
18
 
8
19
  def __init__(self, import_name: str) -> None:
9
20
  super().__init__(import_name)
10
21
 
11
- for k, v in self._RULES.items():
12
- self.add_url_rule(rule=k, view_func=v)
22
+ for rule, view_func in self._RULES.items():
23
+ self.add_url_rule(
24
+ rule=rule,
25
+ view_func=view_func,
26
+ )
13
27
 
14
28
  def serve(self, port: int) -> None:
29
+ """
30
+ Starts this Flask application
31
+ """
32
+
15
33
  waitress.serve(
16
34
  app=self,
17
35
  host="127.0.0.1",
pyquoks/models.py CHANGED
@@ -2,62 +2,137 @@ from __future__ import annotations
2
2
 
3
3
 
4
4
  class IContainer:
5
- _ATTRIBUTES: set[str] = None
5
+ """
6
+ Class for storing lists of models and another parameters
7
+ """
8
+
9
+ _ATTRIBUTES: set[str] | dict[str, set[str]] = None
10
+ """
11
+ Set of parameters that also can be stored one key deep
12
+
13
+ Example:
14
+ _ATTRIBUTES = {"beatmap_id", "score_id"}
15
+
16
+ _ATTRIBUTES = {"attributes": {"max_combo", "star_rating"}}
17
+ """
18
+
6
19
  _DATA: dict[str, type] = None
20
+ """
21
+ Dictionary with name and type of models stored in list inside ``json_data``
22
+
23
+ Example:
24
+ _DATA = {"scores": ScoreModel}
25
+ """
26
+
7
27
  _OBJECTS: dict[str, type] = None
8
- data: dict
28
+ """
29
+ Dictionary with keys of ``json_data`` and types of models stored in a list inside
30
+
31
+ Example:
32
+ _OBJECTS = {"beatmaps": BeatmapModel, "scores": ScoreModel}
33
+ """
34
+
35
+ _data: dict
36
+ """
37
+ Initial data that was passed into object
38
+ """
9
39
 
10
40
  def __init__(self, json_data: dict) -> None:
11
- setattr(self, "data", json_data)
41
+ self._data = json_data
42
+
12
43
  if isinstance(self._ATTRIBUTES, set):
13
- for i in self._ATTRIBUTES:
14
- setattr(self, i, self.data.get(i, None))
44
+ for name in self._ATTRIBUTES:
45
+ setattr(self, name, self._data.get(name, None))
46
+ elif isinstance(self._ATTRIBUTES, dict):
47
+ for key, attributes in self._ATTRIBUTES.items():
48
+ if isinstance(attributes, set):
49
+ for name in attributes:
50
+ try:
51
+ setattr(self, name, self._data.get(key).get(name, None))
52
+ except:
53
+ setattr(self, name, None)
54
+
15
55
  if isinstance(self._DATA, dict):
16
- for k, v in self._DATA.items():
56
+ for name, data_class in self._DATA.items():
17
57
  try:
18
- setattr(self, k, [v(i) for i in self.data])
58
+ setattr(self, name, [data_class(data) for data in self._data])
19
59
  except:
20
- setattr(self, k, None)
60
+ setattr(self, name, None)
21
61
  elif isinstance(self._OBJECTS, dict):
22
- for k, v in self._OBJECTS.items():
62
+ for name, data_class in self._OBJECTS.items():
23
63
  try:
24
- setattr(self, k, [v(i) for i in self.data.get(k)])
64
+ setattr(self, name, [data_class(data) for data in self._data.get(name)])
25
65
  except:
26
- setattr(self, k, None)
66
+ setattr(self, name, None)
27
67
 
28
68
 
29
69
  class IModel:
70
+ """
71
+ Class for storing parameters and models
72
+ """
73
+
30
74
  _ATTRIBUTES: set[str] | dict[str, set[str]] = None
75
+ """
76
+ Set of parameters that also can be stored one key deep
77
+
78
+ Example:
79
+ _ATTRIBUTES = {"beatmap_id", "score_id"}
80
+
81
+ _ATTRIBUTES = {"attributes": {"max_combo", "star_rating"}}
82
+ """
83
+
31
84
  _OBJECTS: dict[str, type] = None
32
- data: dict | list[dict]
85
+ """
86
+ Dictionary with attributes and their models
87
+
88
+ Example:
89
+ _OBJECTS = {"score": ScoreModel}
90
+ """
91
+
92
+ _data: dict | list[dict]
93
+ """
94
+ Initial data that was passed into object
95
+ """
33
96
 
34
97
  def __init__(self, json_data: dict | list[dict]) -> None:
35
- setattr(self, "data", json_data)
98
+ self._data = json_data
99
+
36
100
  if isinstance(self._ATTRIBUTES, set):
37
- for i in self._ATTRIBUTES:
38
- setattr(self, i, self.data.get(i, None))
101
+ for name in self._ATTRIBUTES:
102
+ setattr(self, name, self._data.get(name, None))
39
103
  elif isinstance(self._ATTRIBUTES, dict):
40
- for k, v in self._ATTRIBUTES.items():
41
- if isinstance(v, set):
42
- for i in v:
104
+ for key, attributes in self._ATTRIBUTES.items():
105
+ if isinstance(attributes, set):
106
+ for name in attributes:
43
107
  try:
44
- setattr(self, i, self.data.get(k).get(i, None))
108
+ setattr(self, name, self._data.get(key).get(name, None))
45
109
  except:
46
- setattr(self, i, None)
110
+ setattr(self, name, None)
111
+
47
112
  if isinstance(self._OBJECTS, dict):
48
- for k, v in self._OBJECTS.items():
113
+ for name, data_class in self._OBJECTS.items():
49
114
  try:
50
- setattr(self, k, v(self.data.get(k)))
115
+ setattr(self, name, data_class(self._data.get(name)))
51
116
  except:
52
- setattr(self, k, None)
117
+ setattr(self, name, None)
53
118
 
54
119
 
55
120
  class IValues:
121
+ """
122
+ Class for storing various parameters and values
123
+ """
124
+
56
125
  _ATTRIBUTES: set[str] = None
126
+ """
127
+ Attributes that can be stored in this class
128
+
129
+ Example:
130
+ _ATTRIBUTES = {"settings", "path"}
131
+ """
57
132
 
58
133
  def __init__(self, **kwargs) -> None:
59
- for i in self._ATTRIBUTES:
60
- setattr(self, i, kwargs.get(i, None))
134
+ for name in self._ATTRIBUTES:
135
+ setattr(self, name, kwargs.get(name, None))
61
136
 
62
137
  def update(self, **kwargs) -> None:
63
138
  self.__init__(**kwargs)
pyquoks/utils.py CHANGED
@@ -3,6 +3,10 @@ import sys, os
3
3
 
4
4
 
5
5
  def get_path(relative_path: str, only_abspath: bool = False) -> str:
6
+ """
7
+ :return: Absolute path for provided relative path
8
+ """
9
+
6
10
  try:
7
11
  # noinspection PyUnresolvedReferences
8
12
  base_path = sys._MEIPASS
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyquoks
3
- Version: 1.2.2
3
+ Version: 1.3.0
4
4
  Summary: Пакет PyPI для часто используемых модулей в проектах diquoks
5
5
  Home-page: https://diquoks.ru
6
6
  Author: Denis Titovets
@@ -12,7 +12,7 @@ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: blinker==1.9.0
15
- Requires-Dist: certifi==2025.8.3
15
+ Requires-Dist: certifi==2025.10.5
16
16
  Requires-Dist: charset-normalizer==3.4.3
17
17
  Requires-Dist: click==8.3.0
18
18
  Requires-Dist: colorama==0.4.6
@@ -20,7 +20,7 @@ Requires-Dist: Flask==3.1.2
20
20
  Requires-Dist: idna==3.10
21
21
  Requires-Dist: itsdangerous==2.2.0
22
22
  Requires-Dist: Jinja2==3.1.6
23
- Requires-Dist: MarkupSafe==3.0.2
23
+ Requires-Dist: MarkupSafe==3.0.3
24
24
  Requires-Dist: pillow==11.3.0
25
25
  Requires-Dist: requests==2.32.5
26
26
  Requires-Dist: urllib3==2.5.0
@@ -0,0 +1,10 @@
1
+ pyquoks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pyquoks/data.py,sha256=5PkERLBiNmuEYy8mYTe2AWUUEPt3lAtH5tG9TlyBl4w,15399
3
+ pyquoks/localhost.py,sha256=2sl1CovYrnIzBYW-eKDIYOfi5bUsSVTAdQobzAHpIys,828
4
+ pyquoks/models.py,sha256=kdduuHgh8RLe8_S5Lmv3jS6hqsZG-oYQhPTgk2C11ug,4171
5
+ pyquoks/utils.py,sha256=lcHZyIFIflGMqAhDkqm8GWOUFwb2f-IHgIPZxEiHBz0,484
6
+ pyquoks-1.3.0.dist-info/licenses/LICENSE,sha256=eEd8UIYxvKUY7vqrV1XTFo70_FQdiW6o1fznseCXRJs,1095
7
+ pyquoks-1.3.0.dist-info/METADATA,sha256=sCQPZSFYT7zfM4hFygVOeCWHXz1QEt7i9oOzhmKGNgw,1802
8
+ pyquoks-1.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ pyquoks-1.3.0.dist-info/top_level.txt,sha256=4Eqn44TCCp-D8V6To92e8-KKr49ZGf0dCcsdRQmPkhc,8
10
+ pyquoks-1.3.0.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- pyquoks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- pyquoks/data.py,sha256=S74VxkQtTQipfa1Z7LYiU5RTWSxhnGNhbtv0PB3glf4,8124
3
- pyquoks/localhost.py,sha256=mu55k4d1AZJ77IwavvOEEz9m3fNI6s_q97MSb90vy2Y,494
4
- pyquoks/models.py,sha256=_2mxn7nBZzm8jALJSKcFHal06RGh2whHYp7De-bBxqk,2187
5
- pyquoks/utils.py,sha256=5WswiChwsjJK3IWADizh_JnW0hmIP4PJQyXmhNlPExs,409
6
- pyquoks-1.2.2.dist-info/licenses/LICENSE,sha256=eEd8UIYxvKUY7vqrV1XTFo70_FQdiW6o1fznseCXRJs,1095
7
- pyquoks-1.2.2.dist-info/METADATA,sha256=Kx5JgLsBKQT4nAjuySiVNUiW2PObgh5H7isZZCwpykA,1801
8
- pyquoks-1.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- pyquoks-1.2.2.dist-info/top_level.txt,sha256=4Eqn44TCCp-D8V6To92e8-KKr49ZGf0dCcsdRQmPkhc,8
10
- pyquoks-1.2.2.dist-info/RECORD,,