potato-util 0.0.5__py3-none-any.whl → 0.2.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.
@@ -1 +1 @@
1
- __version__ = "0.0.5"
1
+ __version__ = "0.2.0"
potato_util/_base.py CHANGED
@@ -6,6 +6,8 @@ import logging
6
6
 
7
7
  from pydantic import validate_call
8
8
 
9
+ from .validator import is_truthy
10
+
9
11
 
10
12
  logger = logging.getLogger(__name__)
11
13
 
@@ -78,8 +80,28 @@ def get_slug_name(file_path: str | None = None) -> str:
78
80
  return _slug_name
79
81
 
80
82
 
83
+ def is_debug_mode() -> bool:
84
+ """Check if the application is running in debug mode based on environment variables.
85
+
86
+ Returns:
87
+ bool: True if in debug mode, False otherwise.
88
+ """
89
+
90
+ _is_debug = False
91
+ _debug = os.getenv("DEBUG", "").strip().lower()
92
+ if _debug and is_truthy(_debug):
93
+ _is_debug = True
94
+
95
+ _env = os.getenv("ENV", "").strip().lower()
96
+ if (_env == "development") and (_debug == ""):
97
+ _is_debug = True
98
+
99
+ return _is_debug
100
+
101
+
81
102
  __all__ = [
82
103
  "deep_merge",
83
104
  "camel_to_snake",
84
105
  "get_slug_name",
106
+ "is_debug_mode",
85
107
  ]
potato_util/io/_async.py CHANGED
@@ -1,7 +1,21 @@
1
+ import sys
2
+ import json
1
3
  import errno
2
4
  import hashlib
3
5
  import logging
6
+ import configparser
7
+ from pathlib import Path
8
+ from typing import Any
4
9
 
10
+ _binary_toml = False
11
+ if sys.version_info >= (3, 11):
12
+ import tomllib # type: ignore
13
+
14
+ _binary_toml = True
15
+ else:
16
+ import toml as tomllib # type: ignore
17
+
18
+ import yaml
5
19
  import aioshutil
6
20
  import aiofiles.os
7
21
  from pydantic import validate_call
@@ -276,6 +290,195 @@ async def async_get_file_checksum(
276
290
  return _file_checksum
277
291
 
278
292
 
293
+ @validate_call
294
+ async def async_read_yaml_file(file_path: str | Path) -> dict[str, Any]:
295
+ """Asynchronous read YAML file.
296
+
297
+ Args:
298
+ file_path (str | Path, required): YAML file path.
299
+
300
+ Raises:
301
+ FileNotFoundError: If YAML file is not found.
302
+ Exception : If failed to read YAML file.
303
+
304
+ Returns:
305
+ dict[str, Any]: YAML file data as dictionary.
306
+ """
307
+
308
+ _data: dict[str, Any] = {}
309
+
310
+ if isinstance(file_path, str):
311
+ file_path = Path(file_path)
312
+
313
+ if not await aiofiles.os.path.isfile(file_path):
314
+ raise FileNotFoundError(f"Not found '{file_path}' YAML file!")
315
+
316
+ try:
317
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
318
+ _content = await _file.read()
319
+ _data = yaml.safe_load(_content) or {}
320
+ except Exception:
321
+ logger.error(f"Failed to read '{file_path}' YAML file!")
322
+ raise
323
+
324
+ return _data
325
+
326
+
327
+ @validate_call
328
+ async def async_read_json_file(file_path: str | Path) -> dict[str, Any]:
329
+ """Asynchronous read JSON file.
330
+
331
+ Args:
332
+ file_path (str | Path, required): JSON file path.
333
+
334
+ Raises:
335
+ FileNotFoundError: If JSON file is not found.
336
+ Exception : If failed to read JSON file.
337
+
338
+ Returns:
339
+ dict[str, Any]: JSON file data as dictionary.
340
+ """
341
+
342
+ _data: dict[str, Any] = {}
343
+
344
+ if isinstance(file_path, str):
345
+ file_path = Path(file_path)
346
+
347
+ if not await aiofiles.os.path.isfile(file_path):
348
+ raise FileNotFoundError(f"Not found '{file_path}' JSON file!")
349
+
350
+ try:
351
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
352
+ _content = await _file.read()
353
+ _data = json.loads(_content) or {}
354
+ except Exception:
355
+ logger.error(f"Failed to read '{file_path}' JSON file!")
356
+ raise
357
+
358
+ return _data
359
+
360
+
361
+ @validate_call
362
+ async def async_read_toml_file(file_path: str | Path) -> dict[str, Any]:
363
+ """Asynchronous read TOML file.
364
+
365
+ Args:
366
+ file_path (str | Path, required): TOML file path.
367
+
368
+ Raises:
369
+ FileNotFoundError: If TOML file is not found.
370
+ Exception : If failed to read TOML file.
371
+
372
+ Returns:
373
+ dict[str, Any]: TOML file data as dictionary.
374
+ """
375
+
376
+ _data: dict[str, Any] = {}
377
+
378
+ if isinstance(file_path, str):
379
+ file_path = Path(file_path)
380
+
381
+ if not await aiofiles.os.path.isfile(file_path):
382
+ raise FileNotFoundError(f"Not found '{file_path}' TOML file!")
383
+
384
+ try:
385
+ _content: str = ""
386
+ if _binary_toml:
387
+ async with aiofiles.open(file_path, "rb") as _file:
388
+ _content = await _file.read() # type: ignore
389
+ _data = tomllib.load(_content) or {}
390
+ else:
391
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
392
+ _content = await _file.read() # type: ignore
393
+ _data = tomllib.loads(_content) or {}
394
+
395
+ except Exception:
396
+ logger.error(f"Failed to read '{file_path}' TOML file!")
397
+ raise
398
+
399
+ return _data
400
+
401
+
402
+ @validate_call
403
+ async def async_read_ini_file(file_path: str | Path) -> dict[str, Any]:
404
+ """Asynchronous read INI config file.
405
+
406
+ Args:
407
+ file_path (str | Path, required): INI config file path.
408
+
409
+ Raises:
410
+ FileNotFoundError: If INI config file is not found.
411
+ Exception : If failed to read INI config file.
412
+
413
+ Returns:
414
+ dict[str, Any]: INI config file data as dictionary.
415
+ """
416
+
417
+ _config: dict[str, Any] = {}
418
+
419
+ if isinstance(file_path, str):
420
+ file_path = Path(file_path)
421
+
422
+ if not await aiofiles.os.path.isfile(file_path):
423
+ raise FileNotFoundError(f"Not found '{file_path}' INI config file!")
424
+
425
+ try:
426
+ _content: str = ""
427
+ async with aiofiles.open(file_path, "r", encoding="utf-8") as _file:
428
+ _content = await _file.read()
429
+
430
+ _config_parser = configparser.ConfigParser()
431
+ _config_parser.read_string(_content)
432
+ for _section in _config_parser.sections():
433
+ _config[_section] = dict(_config_parser.items(_section))
434
+
435
+ except Exception:
436
+ logger.error(f"Failed to read '{file_path}' INI config file!")
437
+ raise
438
+
439
+ return _config
440
+
441
+
442
+ @validate_call
443
+ async def async_read_config_file(config_path: str | Path) -> dict[str, Any]:
444
+ """Asynchronous read config file (YAML, JSON, TOML, INI).
445
+
446
+ Args:
447
+ config_path (str | Path, required): Config file path.
448
+
449
+ Raises:
450
+ FileNotFoundError: If config file is not found.
451
+ ValueError : If config file format is not supported.
452
+
453
+ Returns:
454
+ dict[str, Any]: Config file data as dictionary.
455
+ """
456
+
457
+ _config: dict[str, Any] = {}
458
+
459
+ if isinstance(config_path, str):
460
+ config_path = Path(config_path)
461
+
462
+ if not await aiofiles.os.path.isfile(config_path):
463
+ raise FileNotFoundError(f"Not found '{config_path}' config file!")
464
+
465
+ _suffix = config_path.suffix.lower()
466
+ if _suffix in (".yaml", ".yml"):
467
+ _config = await async_read_yaml_file(config_path)
468
+ elif _suffix == ".json":
469
+ _config = await async_read_json_file(config_path)
470
+ elif _suffix == ".toml":
471
+ _config = await async_read_toml_file(config_path)
472
+ elif _suffix in (".ini", ".cfg"):
473
+ _config = await async_read_ini_file(config_path)
474
+ else:
475
+ raise ValueError(
476
+ f"Unsupported config file format '{_suffix}' for '{config_path}'!"
477
+ )
478
+
479
+ return _config
480
+
481
+
279
482
  __all__ = [
280
483
  "async_create_dir",
281
484
  "async_remove_dir",
@@ -283,4 +486,9 @@ __all__ = [
283
486
  "async_remove_file",
284
487
  "async_remove_files",
285
488
  "async_get_file_checksum",
489
+ "async_read_yaml_file",
490
+ "async_read_json_file",
491
+ "async_read_toml_file",
492
+ "async_read_ini_file",
493
+ "async_read_config_file",
286
494
  ]
potato_util/io/_sync.py CHANGED
@@ -1,11 +1,28 @@
1
+ # noqa: E402
2
+
1
3
  import os
4
+ import sys
5
+ import json
2
6
  import errno
3
7
  import shutil
4
8
  import hashlib
5
9
  import logging
10
+ import configparser
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ _binary_toml = False
15
+ if sys.version_info >= (3, 11):
16
+ import tomllib # type: ignore
17
+
18
+ _binary_toml = True
19
+ else:
20
+ import toml as tomllib # type: ignore
6
21
 
22
+ import yaml
7
23
  from pydantic import validate_call
8
24
 
25
+
9
26
  from ..constants import WarnEnum, HashAlgoEnum, MAX_PATH_LENGTH
10
27
 
11
28
 
@@ -270,6 +287,185 @@ def get_file_checksum(
270
287
  return _file_checksum
271
288
 
272
289
 
290
+ @validate_call
291
+ def read_yaml_file(file_path: str | Path) -> dict[str, Any]:
292
+ """Read YAML file.
293
+
294
+ Args:
295
+ file_path (str | Path, required): YAML file path.
296
+
297
+ Raises:
298
+ FileNotFoundError: If YAML file is not found.
299
+ Exception : If failed to read YAML file.
300
+
301
+ Returns:
302
+ dict[str, Any]: YAML file data as dictionary.
303
+ """
304
+
305
+ _data: dict[str, Any] = {}
306
+
307
+ if isinstance(file_path, str):
308
+ file_path = Path(file_path)
309
+
310
+ if not os.path.isfile(file_path):
311
+ raise FileNotFoundError(f"Not found '{file_path}' YAML file!")
312
+
313
+ try:
314
+ with open(file_path, encoding="utf-8") as _file:
315
+ _data = yaml.safe_load(_file) or {}
316
+ except Exception:
317
+ logger.error(f"Failed to read '{file_path}' YAML file!")
318
+ raise
319
+
320
+ return _data
321
+
322
+
323
+ @validate_call
324
+ def read_json_file(file_path: str | Path) -> dict[str, Any]:
325
+ """Read JSON file.
326
+
327
+ Args:
328
+ file_path (str | Path, required): JSON file path.
329
+
330
+ Raises:
331
+ FileNotFoundError: If JSON file is not found.
332
+ Exception : If failed to read JSON file.
333
+
334
+ Returns:
335
+ dict[str, Any]: JSON file data as dictionary.
336
+ """
337
+
338
+ _data: dict[str, Any] = {}
339
+
340
+ if isinstance(file_path, str):
341
+ file_path = Path(file_path)
342
+
343
+ if not os.path.isfile(file_path):
344
+ raise FileNotFoundError(f"Not found '{file_path}' JSON file!")
345
+
346
+ try:
347
+ with open(file_path, encoding="utf-8") as _file:
348
+ _data = json.load(_file) or {}
349
+ except Exception:
350
+ logger.error(f"Failed to read '{file_path}' JSON file!")
351
+ raise
352
+
353
+ return _data
354
+
355
+
356
+ @validate_call
357
+ def read_toml_file(file_path: str | Path) -> dict[str, Any]:
358
+ """Read TOML file.
359
+
360
+ Args:
361
+ file_path (str | Path, required): TOML file path.
362
+
363
+ Raises:
364
+ FileNotFoundError: If TOML file is not found.
365
+ Exception : If failed to read TOML file.
366
+
367
+ Returns:
368
+ dict[str, Any]: TOML file data as dictionary.
369
+ """
370
+
371
+ _data: dict[str, Any] = {}
372
+
373
+ if isinstance(file_path, str):
374
+ file_path = Path(file_path)
375
+
376
+ if not os.path.isfile(file_path):
377
+ raise FileNotFoundError(f"Not found '{file_path}' TOML file!")
378
+
379
+ try:
380
+ if _binary_toml:
381
+ with open(file_path, "rb") as _file:
382
+ _data = tomllib.load(_file) or {} # type: ignore
383
+ else:
384
+ with open(file_path, encoding="utf-8") as _file:
385
+ _data = tomllib.load(_file) or {} # type: ignore
386
+ except Exception:
387
+ logger.error(f"Failed to read '{file_path}' TOML file!")
388
+ raise
389
+
390
+ return _data
391
+
392
+
393
+ @validate_call
394
+ def read_ini_file(file_path: str | Path) -> dict[str, Any]:
395
+ """Read INI config file.
396
+
397
+ Args:
398
+ file_path (str | Path, required): INI config file path.
399
+
400
+ Raises:
401
+ FileNotFoundError: If INI config file is not found.
402
+ Exception : If failed to read INI config file.
403
+
404
+ Returns:
405
+ dict[str, Any]: INI config file data as dictionary.
406
+ """
407
+
408
+ _config: dict[str, Any] = {}
409
+
410
+ if isinstance(file_path, str):
411
+ file_path = Path(file_path)
412
+
413
+ if not os.path.isfile(file_path):
414
+ raise FileNotFoundError(f"Not found '{file_path}' INI config file!")
415
+
416
+ try:
417
+ _config_parser = configparser.ConfigParser()
418
+ _config_parser.read(file_path)
419
+ for _section in _config_parser.sections():
420
+ _config[_section] = dict(_config_parser.items(_section))
421
+
422
+ except Exception:
423
+ logger.error(f"Failed to read '{file_path}' INI config file!")
424
+ raise
425
+
426
+ return _config
427
+
428
+
429
+ @validate_call
430
+ def read_config_file(config_path: str | Path) -> dict[str, Any]:
431
+ """Read config file (YAML, JSON, TOML, INI).
432
+
433
+ Args:
434
+ config_path (str | Path, required): Config file path.
435
+
436
+ Raises:
437
+ FileNotFoundError: If config file is not found.
438
+ ValueError : If config file format is not supported.
439
+
440
+ Returns:
441
+ dict[str, Any]: Config file data as dictionary.
442
+ """
443
+
444
+ _config: dict[str, Any] = {}
445
+
446
+ if isinstance(config_path, str):
447
+ config_path = Path(config_path)
448
+
449
+ if not os.path.isfile(config_path):
450
+ raise FileNotFoundError(f"Not found '{config_path}' config file!")
451
+
452
+ _suffix = config_path.suffix.lower()
453
+ if _suffix in (".yaml", ".yml"):
454
+ _config = read_yaml_file(file_path=config_path)
455
+ elif _suffix == ".json":
456
+ _config = read_json_file(file_path=config_path)
457
+ elif _suffix == ".toml":
458
+ _config = read_toml_file(file_path=config_path)
459
+ elif _suffix in (".ini", ".cfg"):
460
+ _config = read_ini_file(file_path=config_path)
461
+ else:
462
+ raise ValueError(
463
+ f"Unsupported config file format '{config_path.suffix}' for '{config_path}'!"
464
+ )
465
+
466
+ return _config
467
+
468
+
273
469
  __all__ = [
274
470
  "create_dir",
275
471
  "remove_dir",
@@ -277,4 +473,9 @@ __all__ = [
277
473
  "remove_file",
278
474
  "remove_files",
279
475
  "get_file_checksum",
476
+ "read_yaml_file",
477
+ "read_json_file",
478
+ "read_toml_file",
479
+ "read_ini_file",
480
+ "read_config_file",
280
481
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: potato_util
3
- Version: 0.0.5
3
+ Version: 0.2.0
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,26 +21,28 @@ 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
27
29
  Provides-Extra: async
28
- Requires-Dist: aiofiles<25.0.0,>=24.1.0; extra == "async"
30
+ Requires-Dist: aiofiles<26.0.0,>=24.1.0; extra == "async"
29
31
  Requires-Dist: aioshutil<2.0.0,>=1.5; extra == "async"
30
32
  Requires-Dist: aiohttp<4.0.0,>=3.11.18; extra == "async"
31
33
  Provides-Extra: fastapi
32
34
  Requires-Dist: fastapi<1.0.0,>=0.109.2; extra == "fastapi"
33
35
  Provides-Extra: all
34
- Requires-Dist: aiofiles<25.0.0,>=24.1.0; extra == "all"
36
+ Requires-Dist: aiofiles<26.0.0,>=24.1.0; extra == "all"
35
37
  Requires-Dist: aioshutil<2.0.0,>=1.5; extra == "all"
36
38
  Requires-Dist: aiohttp<4.0.0,>=3.11.18; extra == "all"
37
39
  Requires-Dist: fastapi<1.0.0,>=0.109.2; extra == "all"
38
40
  Provides-Extra: test
39
- Requires-Dist: aiofiles<25.0.0,>=24.1.0; extra == "test"
41
+ Requires-Dist: aiofiles<26.0.0,>=24.1.0; extra == "test"
40
42
  Requires-Dist: aioshutil<2.0.0,>=1.5; extra == "test"
41
43
  Requires-Dist: aiohttp<4.0.0,>=3.11.18; extra == "test"
42
44
  Requires-Dist: fastapi<1.0.0,>=0.109.2; extra == "test"
43
- Requires-Dist: pytest<9.0.0,>=8.0.2; extra == "test"
45
+ Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "test"
44
46
  Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "test"
45
47
  Requires-Dist: pytest-xdist<4.0.0,>=3.6.1; extra == "test"
46
48
  Requires-Dist: pytest-benchmark<6.0.0,>=5.0.1; extra == "test"
@@ -50,17 +52,17 @@ Requires-Dist: wheel<1.0.0,>=0.43.0; extra == "build"
50
52
  Requires-Dist: build<2.0.0,>=1.1.1; extra == "build"
51
53
  Requires-Dist: twine<7.0.0,>=6.0.1; extra == "build"
52
54
  Provides-Extra: docs
53
- Requires-Dist: pylint<4.0.0,>=3.0.4; extra == "docs"
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
58
  Requires-Dist: mkdocstrings[python]<1.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
- Requires-Dist: aiofiles<25.0.0,>=24.1.0; extra == "dev"
61
+ Requires-Dist: aiofiles<26.0.0,>=24.1.0; extra == "dev"
60
62
  Requires-Dist: aioshutil<2.0.0,>=1.5; extra == "dev"
61
63
  Requires-Dist: aiohttp<4.0.0,>=3.11.18; extra == "dev"
62
64
  Requires-Dist: fastapi<1.0.0,>=0.109.2; extra == "dev"
63
- Requires-Dist: pytest<9.0.0,>=8.0.2; extra == "dev"
65
+ Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "dev"
64
66
  Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "dev"
65
67
  Requires-Dist: pytest-xdist<4.0.0,>=3.6.1; extra == "dev"
66
68
  Requires-Dist: pytest-benchmark<6.0.0,>=5.0.1; extra == "dev"
@@ -68,7 +70,7 @@ Requires-Dist: setuptools<81.0.0,>=70.3.0; extra == "dev"
68
70
  Requires-Dist: wheel<1.0.0,>=0.43.0; extra == "dev"
69
71
  Requires-Dist: build<2.0.0,>=1.1.1; extra == "dev"
70
72
  Requires-Dist: twine<7.0.0,>=6.0.1; extra == "dev"
71
- Requires-Dist: pylint<4.0.0,>=3.0.4; extra == "dev"
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
76
  Requires-Dist: mkdocstrings[python]<1.0.0,>=0.24.3; extra == "dev"
@@ -1,6 +1,6 @@
1
1
  potato_util/__init__.py,sha256=xl4th2Z_OmTk-3aO1w05Vh8ob0BnX4RcY1fT9tGX61c,74
2
- potato_util/__version__.py,sha256=S7u1lbuWmM3A3ajykBialmPoJUK6Jg-WmNqM-9OZFdk,22
3
- potato_util/_base.py,sha256=yWj687li7meg1d7AH1e5rztoyL7z59JunKcBGoDUUJs,2014
2
+ potato_util/__version__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
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
6
6
  potato_util/sanitizer.py,sha256=pZuMDvZxKKIdwFKTcqfmHb9ji-UefSgRgJ8ynHG6UFs,2267
@@ -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.0.5.dist-info/licenses/LICENSE.txt,sha256=CUTK-r0BWIg1r0bBiemAcMhakgV0N7HuRhw6rQ-A9A4,1074
22
- potato_util-0.0.5.dist-info/METADATA,sha256=N5tIucIltyII95e7Q46MW_p8pmUmrfBvUkO_ntDBreQ,15634
23
- potato_util-0.0.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- potato_util-0.0.5.dist-info/top_level.txt,sha256=pLMnSfT6rhlYBpo2Gnd8kKMDxcuvxdVizqsv1dd1frw,12
25
- potato_util-0.0.5.dist-info/RECORD,,
19
+ potato_util/io/_async.py,sha256=TViNNR1yHGMoSk-YuBBo7n7FdHcIiu1wMJqc9B7eJDY,15855
20
+ potato_util/io/_sync.py,sha256=sTu0D9zQBmnPYnERFVWohKYNM6FJycAQ_WXkCNsVJuE,14828
21
+ potato_util-0.2.0.dist-info/licenses/LICENSE.txt,sha256=CUTK-r0BWIg1r0bBiemAcMhakgV0N7HuRhw6rQ-A9A4,1074
22
+ potato_util-0.2.0.dist-info/METADATA,sha256=T9U6_lYuXtH9x9OqpXNQc6X2V2fCdCdP98t0Z2OSb_o,15725
23
+ potato_util-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ potato_util-0.2.0.dist-info/top_level.txt,sha256=pLMnSfT6rhlYBpo2Gnd8kKMDxcuvxdVizqsv1dd1frw,12
25
+ potato_util-0.2.0.dist-info/RECORD,,