potato-util 0.1.0__py3-none-any.whl → 0.2.1__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.
@@ -1 +1 @@
1
- __version__ = "0.1.0"
1
+ __version__ = "0.2.1"
@@ -24,8 +24,16 @@ class HashAlgoEnum(str, Enum):
24
24
  sha512 = "sha512"
25
25
 
26
26
 
27
+ class ConfigFileFormatEnum(str, Enum):
28
+ YAML = "YAML"
29
+ JSON = "JSON"
30
+ TOML = "TOML"
31
+ INI = "INI"
32
+
33
+
27
34
  __all__ = [
28
35
  "WarnEnum",
29
36
  "TSUnitEnum",
30
37
  "HashAlgoEnum",
38
+ "ConfigFileFormatEnum",
31
39
  ]
potato_util/io/_async.py CHANGED
@@ -1,12 +1,29 @@
1
+ import os
2
+ import sys
3
+ import json
4
+ import glob
1
5
  import errno
2
6
  import hashlib
3
7
  import logging
8
+ import configparser
9
+ from pathlib import Path
10
+ from typing import Any
4
11
 
12
+ _binary_toml = False
13
+ if sys.version_info >= (3, 11):
14
+ import tomllib # type: ignore
15
+
16
+ _binary_toml = True
17
+ else:
18
+ import toml as tomllib # type: ignore
19
+
20
+ import yaml
5
21
  import aioshutil
6
22
  import aiofiles.os
7
23
  from pydantic import validate_call
8
24
 
9
- from ..constants import WarnEnum, HashAlgoEnum, MAX_PATH_LENGTH
25
+ from .._base import deep_merge
26
+ from ..constants import WarnEnum, HashAlgoEnum, ConfigFileFormatEnum, MAX_PATH_LENGTH
10
27
 
11
28
 
12
29
  logger = logging.getLogger(__name__)
@@ -276,6 +293,252 @@ async def async_get_file_checksum(
276
293
  return _file_checksum
277
294
 
278
295
 
296
+ @validate_call
297
+ async def async_read_yaml_file(file_path: str | Path) -> dict[str, Any]:
298
+ """Asynchronous read YAML file.
299
+
300
+ Args:
301
+ file_path (str | Path, required): YAML file path.
302
+
303
+ Raises:
304
+ FileNotFoundError: If YAML file is not found.
305
+ Exception : If failed to read YAML file.
306
+
307
+ Returns:
308
+ dict[str, Any]: YAML file data as dictionary.
309
+ """
310
+
311
+ _data: dict[str, Any] = {}
312
+
313
+ if isinstance(file_path, str):
314
+ file_path = Path(file_path)
315
+
316
+ if not await aiofiles.os.path.isfile(file_path):
317
+ raise FileNotFoundError(f"Not found '{file_path}' YAML file!")
318
+
319
+ try:
320
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
321
+ _content = await _file.read()
322
+ _data = yaml.safe_load(_content) or {}
323
+ except Exception:
324
+ logger.error(f"Failed to read '{file_path}' YAML file!")
325
+ raise
326
+
327
+ return _data
328
+
329
+
330
+ @validate_call
331
+ async def async_read_json_file(file_path: str | Path) -> dict[str, Any]:
332
+ """Asynchronous read JSON file.
333
+
334
+ Args:
335
+ file_path (str | Path, required): JSON file path.
336
+
337
+ Raises:
338
+ FileNotFoundError: If JSON file is not found.
339
+ Exception : If failed to read JSON file.
340
+
341
+ Returns:
342
+ dict[str, Any]: JSON file data as dictionary.
343
+ """
344
+
345
+ _data: dict[str, Any] = {}
346
+
347
+ if isinstance(file_path, str):
348
+ file_path = Path(file_path)
349
+
350
+ if not await aiofiles.os.path.isfile(file_path):
351
+ raise FileNotFoundError(f"Not found '{file_path}' JSON file!")
352
+
353
+ try:
354
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
355
+ _content = await _file.read()
356
+ _data = json.loads(_content) or {}
357
+ except Exception:
358
+ logger.error(f"Failed to read '{file_path}' JSON file!")
359
+ raise
360
+
361
+ return _data
362
+
363
+
364
+ @validate_call
365
+ async def async_read_toml_file(file_path: str | Path) -> dict[str, Any]:
366
+ """Asynchronous read TOML file.
367
+
368
+ Args:
369
+ file_path (str | Path, required): TOML file path.
370
+
371
+ Raises:
372
+ FileNotFoundError: If TOML file is not found.
373
+ Exception : If failed to read TOML file.
374
+
375
+ Returns:
376
+ dict[str, Any]: TOML file data as dictionary.
377
+ """
378
+
379
+ _data: dict[str, Any] = {}
380
+
381
+ if isinstance(file_path, str):
382
+ file_path = Path(file_path)
383
+
384
+ if not await aiofiles.os.path.isfile(file_path):
385
+ raise FileNotFoundError(f"Not found '{file_path}' TOML file!")
386
+
387
+ try:
388
+ _content: str = ""
389
+ if _binary_toml:
390
+ async with aiofiles.open(file_path, "rb") as _file:
391
+ _content = await _file.read() # type: ignore
392
+ _data = tomllib.load(_content) or {}
393
+ else:
394
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
395
+ _content = await _file.read() # type: ignore
396
+ _data = tomllib.loads(_content) or {}
397
+
398
+ except Exception:
399
+ logger.error(f"Failed to read '{file_path}' TOML file!")
400
+ raise
401
+
402
+ return _data
403
+
404
+
405
+ @validate_call
406
+ async def async_read_ini_file(file_path: str | Path) -> dict[str, Any]:
407
+ """Asynchronous read INI config file.
408
+
409
+ Args:
410
+ file_path (str | Path, required): INI config file path.
411
+
412
+ Raises:
413
+ FileNotFoundError: If INI config file is not found.
414
+ Exception : If failed to read INI config file.
415
+
416
+ Returns:
417
+ dict[str, Any]: INI config file data as dictionary.
418
+ """
419
+
420
+ _config: dict[str, Any] = {}
421
+
422
+ if isinstance(file_path, str):
423
+ file_path = Path(file_path)
424
+
425
+ if not await aiofiles.os.path.isfile(file_path):
426
+ raise FileNotFoundError(f"Not found '{file_path}' INI config file!")
427
+
428
+ try:
429
+ _content: str = ""
430
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
431
+ _content = await _file.read()
432
+
433
+ _config_parser = configparser.ConfigParser()
434
+ _config_parser.read_string(_content)
435
+ for _section in _config_parser.sections():
436
+ _config[_section] = dict(_config_parser.items(_section))
437
+
438
+ except Exception:
439
+ logger.error(f"Failed to read '{file_path}' INI config file!")
440
+ raise
441
+
442
+ return _config
443
+
444
+
445
+ @validate_call
446
+ async def async_read_config_file(config_path: str | Path) -> dict[str, Any]:
447
+ """Asynchronous read config file (YAML, JSON, TOML, INI).
448
+
449
+ Args:
450
+ config_path (str | Path, required): Config file path.
451
+
452
+ Raises:
453
+ FileNotFoundError: If config file is not found.
454
+ ValueError : If config file format is not supported.
455
+
456
+ Returns:
457
+ dict[str, Any]: Config file data as dictionary.
458
+ """
459
+
460
+ _config: dict[str, Any] = {}
461
+
462
+ if isinstance(config_path, str):
463
+ config_path = Path(config_path)
464
+
465
+ if not await aiofiles.os.path.isfile(config_path):
466
+ raise FileNotFoundError(f"Not found '{config_path}' config file!")
467
+
468
+ _suffix = config_path.suffix.lower()
469
+ if _suffix in (".yaml", ".yml"):
470
+ _config = await async_read_yaml_file(config_path)
471
+ elif _suffix == ".json":
472
+ _config = await async_read_json_file(config_path)
473
+ elif _suffix == ".toml":
474
+ _config = await async_read_toml_file(config_path)
475
+ elif _suffix in (".ini", ".cfg"):
476
+ _config = await async_read_ini_file(config_path)
477
+ else:
478
+ raise ValueError(
479
+ f"Unsupported config file format '{_suffix}' for '{config_path}'!"
480
+ )
481
+
482
+ return _config
483
+
484
+
485
+ @validate_call
486
+ async def async_read_all_configs(
487
+ configs_dir: str | Path | list[str | Path],
488
+ allowed_formats: list[ConfigFileFormatEnum] = [
489
+ ConfigFileFormatEnum.YAML,
490
+ ConfigFileFormatEnum.JSON,
491
+ ConfigFileFormatEnum.TOML,
492
+ ],
493
+ ) -> dict[str, Any]:
494
+ """Asynchronous read all config files from directory or directories and merge them.
495
+
496
+ Args:
497
+ configs_dir (str | Path | list[str | Path], required): Configs directory or directories.
498
+ allowed_formats (list[ConfigFileFormatEnum] , optional): Allowed config file formats to read.
499
+ Defaults to [YAML, JSON, TOML].
500
+
501
+ Returns:
502
+ dict[str, Any]: Dictionary containing all merged config data from all files.
503
+ """
504
+
505
+ _config_dict: dict[str, Any] = {}
506
+
507
+ if not isinstance(configs_dir, list):
508
+ configs_dir = [configs_dir]
509
+
510
+ _file_paths: list[str] = []
511
+ for _config_dir in configs_dir:
512
+ if isinstance(_config_dir, str):
513
+ _config_dir = Path(_config_dir)
514
+
515
+ if not os.path.isabs(_config_dir):
516
+ _current_dir = await aiofiles.os.getcwd()
517
+ _config_dir = os.path.join(_current_dir, _config_dir)
518
+
519
+ if await aiofiles.os.path.isdir(_config_dir):
520
+ if ConfigFileFormatEnum.YAML in allowed_formats:
521
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.yaml")))
522
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.yml")))
523
+
524
+ if ConfigFileFormatEnum.JSON in allowed_formats:
525
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.json")))
526
+
527
+ if ConfigFileFormatEnum.TOML in allowed_formats:
528
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.toml")))
529
+
530
+ if ConfigFileFormatEnum.INI in allowed_formats:
531
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.ini")))
532
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.cfg")))
533
+
534
+ _file_paths.sort()
535
+ for _file_path in _file_paths:
536
+ _config_data = await async_read_config_file(config_path=_file_path)
537
+ _config_dict = deep_merge(_config_dict, _config_data)
538
+
539
+ return _config_dict
540
+
541
+
279
542
  __all__ = [
280
543
  "async_create_dir",
281
544
  "async_remove_dir",
@@ -283,4 +546,10 @@ __all__ = [
283
546
  "async_remove_file",
284
547
  "async_remove_files",
285
548
  "async_get_file_checksum",
549
+ "async_read_yaml_file",
550
+ "async_read_json_file",
551
+ "async_read_toml_file",
552
+ "async_read_ini_file",
553
+ "async_read_config_file",
554
+ "async_read_all_configs",
286
555
  ]
potato_util/io/_sync.py CHANGED
@@ -1,12 +1,30 @@
1
+ # noqa: E402
2
+
1
3
  import os
4
+ import sys
5
+ import json
6
+ import glob
2
7
  import errno
3
8
  import shutil
4
9
  import hashlib
5
10
  import logging
11
+ import configparser
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ _binary_toml = False
16
+ if sys.version_info >= (3, 11):
17
+ import tomllib # type: ignore
6
18
 
19
+ _binary_toml = True
20
+ else:
21
+ import toml as tomllib # type: ignore
22
+
23
+ import yaml
7
24
  from pydantic import validate_call
8
25
 
9
- from ..constants import WarnEnum, HashAlgoEnum, MAX_PATH_LENGTH
26
+ from .._base import deep_merge
27
+ from ..constants import WarnEnum, HashAlgoEnum, ConfigFileFormatEnum, MAX_PATH_LENGTH
10
28
 
11
29
 
12
30
  logger = logging.getLogger(__name__)
@@ -270,6 +288,242 @@ def get_file_checksum(
270
288
  return _file_checksum
271
289
 
272
290
 
291
+ @validate_call
292
+ def read_yaml_file(file_path: str | Path) -> dict[str, Any]:
293
+ """Read YAML file.
294
+
295
+ Args:
296
+ file_path (str | Path, required): YAML file path.
297
+
298
+ Raises:
299
+ FileNotFoundError: If YAML file is not found.
300
+ Exception : If failed to read YAML file.
301
+
302
+ Returns:
303
+ dict[str, Any]: YAML file data as dictionary.
304
+ """
305
+
306
+ _data: dict[str, Any] = {}
307
+
308
+ if isinstance(file_path, str):
309
+ file_path = Path(file_path)
310
+
311
+ if not os.path.isfile(file_path):
312
+ raise FileNotFoundError(f"Not found '{file_path}' YAML file!")
313
+
314
+ try:
315
+ with open(file_path, encoding="utf-8") as _file:
316
+ _data = yaml.safe_load(_file) or {}
317
+ except Exception:
318
+ logger.error(f"Failed to read '{file_path}' YAML file!")
319
+ raise
320
+
321
+ return _data
322
+
323
+
324
+ @validate_call
325
+ def read_json_file(file_path: str | Path) -> dict[str, Any]:
326
+ """Read JSON file.
327
+
328
+ Args:
329
+ file_path (str | Path, required): JSON file path.
330
+
331
+ Raises:
332
+ FileNotFoundError: If JSON file is not found.
333
+ Exception : If failed to read JSON file.
334
+
335
+ Returns:
336
+ dict[str, Any]: JSON file data as dictionary.
337
+ """
338
+
339
+ _data: dict[str, Any] = {}
340
+
341
+ if isinstance(file_path, str):
342
+ file_path = Path(file_path)
343
+
344
+ if not os.path.isfile(file_path):
345
+ raise FileNotFoundError(f"Not found '{file_path}' JSON file!")
346
+
347
+ try:
348
+ with open(file_path, encoding="utf-8") as _file:
349
+ _data = json.load(_file) or {}
350
+ except Exception:
351
+ logger.error(f"Failed to read '{file_path}' JSON file!")
352
+ raise
353
+
354
+ return _data
355
+
356
+
357
+ @validate_call
358
+ def read_toml_file(file_path: str | Path) -> dict[str, Any]:
359
+ """Read TOML file.
360
+
361
+ Args:
362
+ file_path (str | Path, required): TOML file path.
363
+
364
+ Raises:
365
+ FileNotFoundError: If TOML file is not found.
366
+ Exception : If failed to read TOML file.
367
+
368
+ Returns:
369
+ dict[str, Any]: TOML file data as dictionary.
370
+ """
371
+
372
+ _data: dict[str, Any] = {}
373
+
374
+ if isinstance(file_path, str):
375
+ file_path = Path(file_path)
376
+
377
+ if not os.path.isfile(file_path):
378
+ raise FileNotFoundError(f"Not found '{file_path}' TOML file!")
379
+
380
+ try:
381
+ if _binary_toml:
382
+ with open(file_path, "rb") as _file:
383
+ _data = tomllib.load(_file) or {} # type: ignore
384
+ else:
385
+ with open(file_path, encoding="utf-8") as _file:
386
+ _data = tomllib.load(_file) or {} # type: ignore
387
+ except Exception:
388
+ logger.error(f"Failed to read '{file_path}' TOML file!")
389
+ raise
390
+
391
+ return _data
392
+
393
+
394
+ @validate_call
395
+ def read_ini_file(file_path: str | Path) -> dict[str, Any]:
396
+ """Read INI config file.
397
+
398
+ Args:
399
+ file_path (str | Path, required): INI config file path.
400
+
401
+ Raises:
402
+ FileNotFoundError: If INI config file is not found.
403
+ Exception : If failed to read INI config file.
404
+
405
+ Returns:
406
+ dict[str, Any]: INI config file data as dictionary.
407
+ """
408
+
409
+ _config: dict[str, Any] = {}
410
+
411
+ if isinstance(file_path, str):
412
+ file_path = Path(file_path)
413
+
414
+ if not os.path.isfile(file_path):
415
+ raise FileNotFoundError(f"Not found '{file_path}' INI config file!")
416
+
417
+ try:
418
+ _config_parser = configparser.ConfigParser()
419
+ _config_parser.read(file_path)
420
+ for _section in _config_parser.sections():
421
+ _config[_section] = dict(_config_parser.items(_section))
422
+
423
+ except Exception:
424
+ logger.error(f"Failed to read '{file_path}' INI config file!")
425
+ raise
426
+
427
+ return _config
428
+
429
+
430
+ @validate_call
431
+ def read_config_file(config_path: str | Path) -> dict[str, Any]:
432
+ """Read config file (YAML, JSON, TOML, INI).
433
+
434
+ Args:
435
+ config_path (str | Path, required): Config file path.
436
+
437
+ Raises:
438
+ FileNotFoundError: If config file is not found.
439
+ ValueError : If config file format is not supported.
440
+
441
+ Returns:
442
+ dict[str, Any]: Config file data as dictionary.
443
+ """
444
+
445
+ _config: dict[str, Any] = {}
446
+
447
+ if isinstance(config_path, str):
448
+ config_path = Path(config_path)
449
+
450
+ if not os.path.isfile(config_path):
451
+ raise FileNotFoundError(f"Not found '{config_path}' config file!")
452
+
453
+ _suffix = config_path.suffix.lower()
454
+ if _suffix in (".yaml", ".yml"):
455
+ _config = read_yaml_file(file_path=config_path)
456
+ elif _suffix == ".json":
457
+ _config = read_json_file(file_path=config_path)
458
+ elif _suffix == ".toml":
459
+ _config = read_toml_file(file_path=config_path)
460
+ elif _suffix in (".ini", ".cfg"):
461
+ _config = read_ini_file(file_path=config_path)
462
+ else:
463
+ raise ValueError(
464
+ f"Unsupported config file format '{config_path.suffix}' for '{config_path}'!"
465
+ )
466
+
467
+ return _config
468
+
469
+
470
+ @validate_call
471
+ def read_all_configs(
472
+ configs_dir: str | Path | list[str | Path],
473
+ allowed_formats: list[ConfigFileFormatEnum] = [
474
+ ConfigFileFormatEnum.YAML,
475
+ ConfigFileFormatEnum.JSON,
476
+ ConfigFileFormatEnum.TOML,
477
+ ],
478
+ ) -> dict[str, Any]:
479
+ """Read all config files from directory or directories and merge them.
480
+
481
+ Args:
482
+ configs_dir (str | Path | list[str | Path], required): Configs directory or directories.
483
+ allowed_formats (list[ConfigFileFormatEnum] , optional): Allowed config file formats to read.
484
+ Defaults to [YAML, JSON, TOML].
485
+
486
+ Returns:
487
+ dict[str, Any]: Dictionary containing all merged config data from all files.
488
+ """
489
+
490
+ _config_dict: dict[str, Any] = {}
491
+
492
+ if not isinstance(configs_dir, list):
493
+ configs_dir = [configs_dir]
494
+
495
+ _file_paths: list[str] = []
496
+ for _config_dir in configs_dir:
497
+ if isinstance(_config_dir, str):
498
+ _config_dir = Path(_config_dir)
499
+
500
+ if not os.path.isabs(_config_dir):
501
+ _current_dir = os.getcwd()
502
+ _config_dir = os.path.join(_current_dir, _config_dir)
503
+
504
+ if os.path.isdir(_config_dir):
505
+ if ConfigFileFormatEnum.YAML in allowed_formats:
506
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.yaml")))
507
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.yml")))
508
+
509
+ if ConfigFileFormatEnum.JSON in allowed_formats:
510
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.json")))
511
+
512
+ if ConfigFileFormatEnum.TOML in allowed_formats:
513
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.toml")))
514
+
515
+ if ConfigFileFormatEnum.INI in allowed_formats:
516
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.ini")))
517
+ _file_paths.extend(glob.glob(os.path.join(_config_dir, "*.cfg")))
518
+
519
+ _file_paths.sort()
520
+ for _file_path in _file_paths:
521
+ _config_data = read_config_file(config_path=_file_path)
522
+ _config_dict = deep_merge(_config_dict, _config_data)
523
+
524
+ return _config_dict
525
+
526
+
273
527
  __all__ = [
274
528
  "create_dir",
275
529
  "remove_dir",
@@ -277,4 +531,10 @@ __all__ = [
277
531
  "remove_file",
278
532
  "remove_files",
279
533
  "get_file_checksum",
534
+ "read_yaml_file",
535
+ "read_json_file",
536
+ "read_toml_file",
537
+ "read_ini_file",
538
+ "read_config_file",
539
+ "read_all_configs",
280
540
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: potato_util
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: 'potato_util' is collection of simple useful utils package for python.
5
5
  Author-email: Batkhuu Byambajav <batkhuu10@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/bybatkhuu/module-python-utils
@@ -21,6 +21,8 @@ Classifier: Programming Language :: Python :: 3.13
21
21
  Requires-Python: <4.0,>=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE.txt
24
+ Requires-Dist: toml>=0.10.2; python_version < "3.11"
25
+ Requires-Dist: PyYAML<7.0.0,>=6.0.2
24
26
  Requires-Dist: python-dotenv<2.0.0,>=1.0.1
25
27
  Requires-Dist: pydantic[email,timezone]<3.0.0,>=2.0.3
26
28
  Requires-Dist: pydantic-settings<3.0.0,>=2.2.1
@@ -53,7 +55,7 @@ Provides-Extra: docs
53
55
  Requires-Dist: pylint<5.0.0,>=3.0.4; extra == "docs"
54
56
  Requires-Dist: mkdocs-material<10.0.0,>=9.5.50; extra == "docs"
55
57
  Requires-Dist: mkdocs-awesome-nav<4.0.0,>=3.0.0; extra == "docs"
56
- Requires-Dist: mkdocstrings[python]<1.0.0,>=0.24.3; extra == "docs"
58
+ Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "docs"
57
59
  Requires-Dist: mike<3.0.0,>=2.1.3; extra == "docs"
58
60
  Provides-Extra: dev
59
61
  Requires-Dist: aiofiles<26.0.0,>=24.1.0; extra == "dev"
@@ -71,7 +73,7 @@ Requires-Dist: twine<7.0.0,>=6.0.1; extra == "dev"
71
73
  Requires-Dist: pylint<5.0.0,>=3.0.4; extra == "dev"
72
74
  Requires-Dist: mkdocs-material<10.0.0,>=9.5.50; extra == "dev"
73
75
  Requires-Dist: mkdocs-awesome-nav<4.0.0,>=3.0.0; extra == "dev"
74
- Requires-Dist: mkdocstrings[python]<1.0.0,>=0.24.3; extra == "dev"
76
+ Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "dev"
75
77
  Requires-Dist: mike<3.0.0,>=2.1.3; extra == "dev"
76
78
  Requires-Dist: pyright<2.0.0,>=1.1.392; extra == "dev"
77
79
  Requires-Dist: pre-commit<5.0.0,>=4.0.1; extra == "dev"
@@ -1,5 +1,5 @@
1
1
  potato_util/__init__.py,sha256=xl4th2Z_OmTk-3aO1w05Vh8ob0BnX4RcY1fT9tGX61c,74
2
- potato_util/__version__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
2
+ potato_util/__version__.py,sha256=HfjVOrpTnmZ-xVFCYSVmX50EXaBQeJteUHG-PD6iQs8,22
3
3
  potato_util/_base.py,sha256=oKLzp_NheI7kQAKC5xAm77OI_UmBXRuEEpulZTVBg5w,2549
4
4
  potato_util/dt.py,sha256=DatLzuXOxdanplBv-Kf3qOaomrTCUUBSYv_QgTtQB6U,7635
5
5
  potato_util/generator.py,sha256=vdvHj1UrCOQI2WXQHQ2H63PMLQ6yOXAZPNl0m-6BgtY,1572
@@ -8,7 +8,7 @@ potato_util/secure.py,sha256=HxlUGyJl15qiL5WFrTZOJLgBZzuEr3Eu--qvBPmj2So,848
8
8
  potato_util/validator.py,sha256=TANw7uWHi0PANPkrNDOFFvRcYL9Ge75b4xGSf3PTW1A,4083
9
9
  potato_util/constants/__init__.py,sha256=lhxZ2k-QotMR_w9w-Gv-9pCEFrQSKxe1YEIvV83pf8E,80
10
10
  potato_util/constants/_base.py,sha256=J1i611erzcrPRZ6USkVgnNZ_IvvN9YLbcltvyIngpcg,61
11
- potato_util/constants/_enum.py,sha256=tThmf7lFsGfFUNNQE0hOUZ0JKc821ZGZnSyJIj2jVTQ,515
11
+ potato_util/constants/_enum.py,sha256=RYg5MBxeRe2-oZ9CsqvFhDRIvB3Wi4tm-Wa4MLLfVy4,654
12
12
  potato_util/constants/_regex.py,sha256=T7SSsqD0y8jXJJPURwAK2uA59AjLt1uqGfqqUd1a22o,710
13
13
  potato_util/http/__init__.py,sha256=qWOzScMVJEHjzClEqOYmGtfkZyU8f8Hz8nT054Dbblo,229
14
14
  potato_util/http/_async.py,sha256=dfs-ynchPKdnMNQXqyoqhcz-jhtQ7g_4JnNfVr3bXk0,1178
@@ -16,10 +16,10 @@ potato_util/http/_base.py,sha256=qoW5U8gxihVMx3v1gSLLmptMjScVsDS9PowvJ6tTc9c,143
16
16
  potato_util/http/_sync.py,sha256=i8oyRmh-WraOzotaUbssIjOPvBh1pvLPupdoCvyHTK0,1169
17
17
  potato_util/http/fastapi.py,sha256=iqCxZcQDIVtcqCN9dZ4itcoUs6KzsfRGgK7sRd5EmOA,675
18
18
  potato_util/io/__init__.py,sha256=FoGcN7t0uArQV4hbMR1X5aeC8Yq-h_ds4xooNpkmgG0,209
19
- potato_util/io/_async.py,sha256=XVNFDCRII-ib32tksxj5G3nDLsV-ylTW2Hw3_seIY-k,10012
20
- potato_util/io/_sync.py,sha256=ZVRukOYWWvXtVlU_Gf8GoKnQZqSI2LISHPMmxXi4-2U,9644
21
- potato_util-0.1.0.dist-info/licenses/LICENSE.txt,sha256=CUTK-r0BWIg1r0bBiemAcMhakgV0N7HuRhw6rQ-A9A4,1074
22
- potato_util-0.1.0.dist-info/METADATA,sha256=q0H54xuFPSMp-VMTBytUC4e7i7xPE4uEPjrBZ3H3Jl0,15636
23
- potato_util-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- potato_util-0.1.0.dist-info/top_level.txt,sha256=pLMnSfT6rhlYBpo2Gnd8kKMDxcuvxdVizqsv1dd1frw,12
25
- potato_util-0.1.0.dist-info/RECORD,,
19
+ potato_util/io/_async.py,sha256=mFkLrqXreCRJcvWEysS2Tvmb0XEDQeAqnnt1b1NbYh0,18209
20
+ potato_util/io/_sync.py,sha256=Zdvh-2_XeLriI4XKkgsRn9TvI8I3KjQItmIF6w4aNyk,17098
21
+ potato_util-0.2.1.dist-info/licenses/LICENSE.txt,sha256=CUTK-r0BWIg1r0bBiemAcMhakgV0N7HuRhw6rQ-A9A4,1074
22
+ potato_util-0.2.1.dist-info/METADATA,sha256=dPFt_2g3qw7T5cegDm8ZePnoaaM0OT6cHHLAS0Fzzrk,15725
23
+ potato_util-0.2.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
24
+ potato_util-0.2.1.dist-info/top_level.txt,sha256=pLMnSfT6rhlYBpo2Gnd8kKMDxcuvxdVizqsv1dd1frw,12
25
+ potato_util-0.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5