Skip to content

Commit 69b9d51

Browse files
authored
Merge pull request #1 from codesrg/develop
Add files via upload
2 parents 4f5fdb9 + 1c9b537 commit 69b9d51

File tree

11 files changed

+387
-0
lines changed

11 files changed

+387
-0
lines changed

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# IOutil
2+
3+
[![PyPI](https://img.shields.io/pypi/v/ioutil)](https://pypi.python.org/pypi/ioutil)
4+
[![Pypi - License](https://img.shields.io/github/license/codesrg/ioutil)](https://github.com/codesrg/ioutil/blob/main/LICENSE)
5+
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ioutil?color=red)](https://pypi.python.org/pypi/ioutil)
6+
7+
To read and write files.
8+
9+
csv, json, parquet, text, toml formats is supported.
10+
11+
## Installation
12+
13+
`pip install -U ioutil`
14+
15+
## Usage
16+
17+
```
18+
usage: ioutil [options]
19+
20+
optional arguments:
21+
-h, --help show this help message and exit
22+
-v, --version show version number and exit.
23+
24+
to read/write files:
25+
path path to read/write
26+
-r, --read to read file
27+
-w, --write to write file
28+
-d, --data data to write
29+
-f, --format file format to use
30+
-m, --mode mode to open file
31+
--rfv will return formatted string (CSV only)
32+
```
33+
34+
### Python Script
35+
36+
To encrypt/decrypt message using rsa.
37+
38+
```python
39+
from ioutil import csv
40+
41+
data = [['a', 'b'], [[1, 2], [3, 4]]]
42+
path = '.../file.csv'
43+
csv.write(data, path) # to write csv
44+
csv.read(path) # to read csv
45+
```
46+
47+
### Command Line
48+
49+
To write a text file.
50+
51+
```
52+
$ ioutil ".../file.txt" --data "data" --write
53+
True
54+
```
55+
56+
###
57+
58+
To read a json file.
59+
60+
```
61+
$ ioutil ".../file.json" --read
62+
### content of a file ###
63+
```
64+
65+
## Issues:
66+
67+
If you encounter any problems, please file an [issue](https://github.com/codesrg/ioutil/issues) along with a detailed
68+
description.

ioutil/__init__.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""to read and write files"""
2+
3+
from typing import Literal
4+
5+
from ioutil._file import _File
6+
from ioutil._csv import Csv
7+
from ioutil._text import Text
8+
from ioutil._toml import TOML
9+
from ioutil._json import Json
10+
from ioutil._parquet import Parquet
11+
12+
13+
class File:
14+
@staticmethod
15+
def getinstance(_format: Literal["csv", "json", "parquet", "toml", "text"]) -> _File:
16+
_instance = {"csv": Csv, "json": Json, "parquet": Parquet, "toml": TOML, "text": Text}.get(_format)
17+
if not _instance:
18+
_instance = _File
19+
return _instance()
20+
21+
22+
csv = Csv()
23+
json = Json()
24+
parquet = Parquet()
25+
text = Text()
26+
toml = TOML()
27+
28+
__author__ = 'srg'
29+
__version__ = '1.0.0'
30+
31+
__all__ = [
32+
'File',
33+
'csv',
34+
'json',
35+
'parquet',
36+
'toml',
37+
'text'
38+
]

ioutil/__main__.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from __future__ import annotations
2+
3+
import os
4+
import sys
5+
import argparse
6+
from srutil import util
7+
from typing import AnyStr
8+
9+
from . import File, __version__, __package__, __all__
10+
from ._file import _File
11+
12+
13+
def get_argument():
14+
parser = argparse.ArgumentParser(prog=__package__, usage=util.stringbuilder(__package__, " [options]"))
15+
parser.add_argument('-v', '--version', action='version', help='show version number and exit.', version=__version__)
16+
group = parser.add_argument_group("to read/write files")
17+
group.add_argument("path", type=str, help="path to read/write")
18+
group.add_argument("-r", "--read", dest="read", default=False, action="store_true", help="to read file")
19+
group.add_argument("-w", "--write", dest="write", default=False, action="store_true", help="to write file")
20+
group.add_argument("-d", "--data", metavar='', help="data to write")
21+
group.add_argument("-f", "--format", dest='format', metavar='', choices=['csv', 'json', 'parquet', 'text', 'toml'],
22+
type=str, required=False, help="file format to use")
23+
group.add_argument("-m", "--mode", dest="mode", metavar='', default=None, help="mode to open file")
24+
group.add_argument("--rfv", dest="rfv", default=False, action="store_true",
25+
help="will return formatted string (CSV only)")
26+
parser.add_argument_group(group)
27+
options = parser.parse_args()
28+
if not options.format:
29+
_format = list(os.path.splitext(options.path)).pop().lstrip('.')
30+
if _format != 'File' and _format not in __all__:
31+
parser.error("the following arguments are required: -f/--format")
32+
else:
33+
options.format = _format
34+
if not options.read and not options.write:
35+
parser.error("one of the following arguments are required: -r/--read or -w/--write")
36+
if options.read and options.write:
37+
parser.error("any one of the following arguments should be given: -r/--read or -w/--write")
38+
if options.write and not options.data:
39+
parser.error("the following arguments are required: -d/--data")
40+
return options
41+
42+
43+
def _remove_unwanted_params(f: _File, params: dict) -> dict:
44+
method_list = {'read': f.read, 'write': f.write}
45+
params_of_method = util.paramsofmethod(method_list.get(util.whocalledme())).keys()
46+
new_params = dict()
47+
for key, value in params.items():
48+
if key in params_of_method:
49+
new_params.setdefault(key, value)
50+
return new_params
51+
52+
53+
def read(f: _File, path: AnyStr | os.PathLike, **kwargs):
54+
kwargs = _remove_unwanted_params(f, kwargs)
55+
data = f.read(path=path, **kwargs)
56+
print(data)
57+
58+
59+
def write(f: _File, data, path: AnyStr | os.PathLike, **kwargs):
60+
kwargs = _remove_unwanted_params(f, kwargs)
61+
status = f.write(data=data, path=path, **kwargs)
62+
print(status)
63+
64+
65+
def main():
66+
options = get_argument()
67+
f = File.getinstance(options.format)
68+
mode = options.mode if options.mode else 'w' if options.write else 'r'
69+
if options.read:
70+
read(f, options.path, mode=mode, _rfv=options.rfv)
71+
elif options.write:
72+
write(f, options.data, options.path, mode=mode)
73+
74+
75+
if __name__ == "__main__":
76+
sys.exit(main())

ioutil/_csv.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from __future__ import annotations
2+
import os
3+
import csv
4+
from srutil import util
5+
from typing import AnyStr, Dict, List
6+
7+
from ._file import _File
8+
9+
10+
class Csv(_File):
11+
12+
def write(self, data: List[List, List[Dict | List]], path: AnyStr | os.PathLike[AnyStr], mode: str = 'w') -> bool:
13+
fields = data.__getitem__(0)
14+
rows = data.__getitem__(1)
15+
with self._get_stream(path, mode) as csvfile:
16+
if isinstance(rows.__getitem__(0), list):
17+
csvwriter = csv.writer(csvfile)
18+
csvwriter.writerow(fields)
19+
csvwriter.writerows(rows)
20+
elif isinstance(rows.__getitem__(0), dict):
21+
csvwriter = csv.DictWriter(csvfile, fieldnames=fields)
22+
csvwriter.writeheader()
23+
csvwriter.writerows(rows)
24+
return os.path.exists(path)
25+
26+
def read(self, path: AnyStr | os.PathLike[AnyStr], mode: str = 'r', _rfv: bool = False) -> List[List] | str:
27+
"""
28+
:param path: path to target file
29+
:param mode: reading mode
30+
:param _rfv: True will return formatted string
31+
:return: list of values or formatted string
32+
"""
33+
to_return = list()
34+
with self._get_stream(path, mode) as csvfile:
35+
for line in csv.reader(csvfile):
36+
to_return.append(line)
37+
return util.tabulate(to_return) if _rfv else to_return

ioutil/_file.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from __future__ import annotations
2+
3+
import abc
4+
import os
5+
from srutil import util
6+
from typing import AnyStr
7+
8+
meta_interface = util.metaclass('interface')
9+
10+
11+
class IOInterface(metaclass=meta_interface):
12+
13+
def write(self, data: AnyStr, path: AnyStr | os.PathLike[AnyStr], **kwargs) -> bool:
14+
pass
15+
16+
def read(self, path: AnyStr | os.PathLike[AnyStr], **kwargs):
17+
pass
18+
19+
20+
class _File:
21+
@staticmethod
22+
def _get_stream(file: AnyStr | os.PathLike[AnyStr], mode: str):
23+
return open(file, mode)
24+
25+
@abc.abstractmethod
26+
def write(self, **kwargs) -> bool:
27+
pass
28+
29+
@abc.abstractmethod
30+
def read(self, **kwargs):
31+
pass

ioutil/_json.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from __future__ import annotations
2+
3+
import json
4+
import os
5+
from typing import AnyStr
6+
7+
from ._file import _File
8+
9+
10+
class Json(_File):
11+
12+
def write(self, data: str | dict, path: AnyStr | os.PathLike[AnyStr], mode: str = 'w') -> bool:
13+
_json_obj = json.dumps(data)
14+
with self._get_stream(path, mode) as jsonfile:
15+
json.dump(_json_obj, jsonfile)
16+
return os.path.exists(path)
17+
18+
def read(self, path: AnyStr | os.PathLike[AnyStr], mode: str = 'r') -> dict:
19+
"""
20+
:param path: path to target json file
21+
:param mode: reading mode
22+
:return: dict values
23+
"""
24+
with self._get_stream(path, mode) as jsonfile:
25+
return json.load(jsonfile)

ioutil/_parquet.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from __future__ import annotations
2+
3+
import os
4+
import pandas as pd
5+
import pyarrow as pa
6+
import pyarrow.parquet as pq
7+
from typing import AnyStr
8+
9+
from ._file import _File
10+
11+
12+
class Parquet(_File):
13+
14+
def write(self, data: dict, path: AnyStr | os.PathLike[AnyStr]) -> bool:
15+
dataframe = pd.DataFrame.from_dict(data)
16+
table = pa.Table.from_pandas(df=dataframe)
17+
pq.write_table(table, path)
18+
return os.path.exists(path)
19+
20+
def read(self, path: AnyStr | os.PathLike[AnyStr]) -> pd.DataFrame | pd.Series:
21+
"""
22+
:param path: path to target parquet file
23+
:return: pandas dataframe
24+
"""
25+
table = pq.read_table(path)
26+
return table.to_pandas()

ioutil/_text.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from __future__ import annotations
2+
3+
import os
4+
from typing import AnyStr
5+
6+
from ._file import _File
7+
8+
9+
class Text(_File):
10+
11+
def write(self, data: AnyStr, path: AnyStr | os.PathLike[AnyStr], mode: str = 'w') -> bool:
12+
with self._get_stream(path, mode) as textfile:
13+
textfile.write(data)
14+
return os.path.exists(path)
15+
16+
def read(self, path: AnyStr | os.PathLike[AnyStr], mode: str = 'r') -> AnyStr:
17+
"""
18+
:param path: path to target file
19+
:param mode: reading mode
20+
:return: string or bytes
21+
"""
22+
with self._get_stream(path, mode) as textfile:
23+
return textfile.read()

ioutil/_toml.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from __future__ import annotations
2+
3+
import os
4+
import toml
5+
from typing import AnyStr, Any, Mapping
6+
7+
from ._file import _File
8+
9+
10+
class TOML(_File):
11+
12+
def write(self, data: Mapping[str, Any], path: AnyStr | os.PathLike[AnyStr], mode: str = 'w') -> bool:
13+
with self._get_stream(path, mode) as toml_file:
14+
toml.dump(data, toml_file)
15+
return os.path.exists(path)
16+
17+
def read(self, path: AnyStr | os.PathLike[AnyStr], mode: str = 'r') -> dict[str, Any]:
18+
"""
19+
:param path: path to target json file
20+
:param mode: reading mode
21+
:return: dict values
22+
"""
23+
with self._get_stream(path, mode) as toml_file:
24+
return toml.load(toml_file)

pyproject.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[build-system]
2+
requires = ["setuptools>=42"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "ioutil"
7+
version = "1.0.0"
8+
description = "To read and write files."
9+
readme = "README.md"
10+
requires-python = ">=3.6"
11+
license = { text = "Apache License, Version 2.0" }
12+
authors = [
13+
{ name = "srg", email = "[email protected]" },
14+
]
15+
dependencies = [
16+
"toml",
17+
"srutil",
18+
"pandas",
19+
"pyarrow"
20+
]
21+
classifiers = [
22+
"Programming Language :: Python :: 3",
23+
"License :: OSI Approved :: Apache Software License",
24+
"Operating System :: OS Independent",
25+
]
26+
keywords = [
27+
"io", "read", "write", "file", "ioutil"
28+
]
29+
30+
[project.urls]
31+
"Homepage" = "https://github.com/codesrg/ioutil"
32+
"Bug Tracker" = "https://github.com/codesrg/ioutil/issues"
33+
34+
[project.scripts]
35+
ioutil = "ioutil.__main__:main"

0 commit comments

Comments
 (0)