Skip to content

zerohertzLib.util

Util

다양한 format의 data를 hadling하는 함수 및 class들

Modules:

Name Description
csv
data
json

Classes:

Name Description
Json

JSON 형식 file을 읽고 사용하기 위한 class

JsonDir

입력된 경로에 존재하는 JSON 형식 file들을 읽고 사용하기 위한 class

MakeData

JSON file 내 값에 따라 data를 구축하는 class

Functions:

Name Description
find_ext

경로 내 확장자의 수 탐색

read_csv

CSV (Comma-Separated Values) 혹은 TSV (Tab-Separated Values)를 작성하는 function

rmtree

지정한 경로의 file을 삭제하고 다시 생성하는 function

sort_dict

Dictionary를 순서에 맞춰 재배열하는 function

write_csv

CSV (Comma-Separated Values) 혹은 TSV (Tab-Separated Values)를 작성하는 function

write_json

JSON (JavaScript Object Notation)을 작성하는 function

__all__ module-attribute

__all__ = ['Json', 'JsonDir', 'MakeData', 'write_csv', 'write_json', 'read_csv', 'find_ext', 'rmtree', 'sort_dict']

Json

Json(path: str | None = None)

JSON 형식 file을 읽고 사용하기 위한 class

객체 생성 시 path 를 입력하지 않을 시 현재 경로에 존재하는 JSON file을 읽고 path 를 경로로 입력하면 해당 경로에 존재하는 JSON file을 읽는다.

Parameters:

Name Type Description Default
path str | None

JSON file의 경로

None

Attributes:

Name Type Description
name

JSON file 이름

keys

직렬화된 JSON의 key 값들

Examples:

>>> js = zz.util.Json()
>>> js["title"]
'[v0.2.3] Release'
>>> key = js._get_key("color")
>>> key
'labels/LIST/color'
>>> js._get_value(key)
'd73a4a'
>>> js.name
'65.json'
>>> js.keys
['url', 'id', ..., 'assignees/LIST/login', ..., 'active_lock_reason']

Methods:

Name Description
__getitem__

JSON file에서 key에 해당하는 값을 반환

__len__

JSON file의 길이를 반환

get

Json._get_key 로 생성된 key 값을 입력 받아 value return

tree

JSON의 구조를 출력하는 method

Source code in zerohertzLib/util/json.py
def __init__(self, path: str | None = None) -> None:
    if path is None:
        path = glob("*.json")[0]
    elif not path.endswith(".json"):
        path = glob(f"{path}/*.json")[0]
    self.name = path.replace(os.path.dirname(path), "").replace("/", "")
    with open(path, "r", encoding="utf-8") as file:
        self.data = orjson.loads(file.read())
    self.keys = []
    self.map = []

data instance-attribute

data = loads(read())

keys instance-attribute

keys = []

map instance-attribute

map = []

name instance-attribute

name = replace('/', '')

__get_keys

__get_keys(data: Any, key: str = '', front: str = '') -> None
Source code in zerohertzLib/util/json.py
def __get_keys(self, data: Any, key: str = "", front: str = "") -> None:
    if isinstance(data, dict):
        for idx, (key_, val_) in enumerate(data.items()):
            if idx + 1 == len(data):
                self.map.append(front + "└── " + str(key_))
                front_ = " "
            else:
                self.map.append(front + "├── " + str(key_))
                front_ = "│"
            if key:
                self.keys.append(f"{key}/{key_}")
                self.__get_keys(val_, f"{key}/{key_}", front + f"{front_}   ")
            else:
                self.keys.append(f"{key_}")
                self.__get_keys(val_, f"{key_}", front + f"{front_}   ")
    elif isinstance(data, list):
        self.map.append(front + "└── " + "LIST")
        if data:
            if key:
                self.__get_keys(data[0], f"{key}/LIST", front + "    ")
            else:
                self.__get_keys(data[0], "LIST", front + "    ")

__getitem__

__getitem__(key: int | str) -> Any

JSON file에서 key에 해당하는 값을 반환

Parameters:

Name Type Description Default
key int | str

읽어온 JSON file에서 불러올 key 값

required

Returns:

Type Description
Any

Key에 따른 value 값

Source code in zerohertzLib/util/json.py
def __getitem__(self, key: int | str) -> Any:
    """JSON file에서 key에 해당하는 값을 반환

    Args:
        key: 읽어온 JSON file에서 불러올 key 값

    Returns:
        Key에 따른 value 값
    """
    return self.data[key]

__len__

__len__() -> int

JSON file의 길이를 반환

Returns:

Type Description
int

읽어온 JSON file의 길이

Source code in zerohertzLib/util/json.py
def __len__(self) -> int:
    """JSON file의 길이를 반환

    Returns:
        읽어온 JSON file의 길이
    """
    return len(self.data)

_get_key

_get_key(key: str) -> str

Key의 경로를 찾아주는 method

Parameters:

Name Type Description Default
key str

읽어온 JSON file에서 불러올 key 값 (깊이 무관)

required

Returns:

Type Description
str

/ 으로 깊이를 표시한 key 값

Source code in zerohertzLib/util/json.py
def _get_key(self, key: str) -> str:
    """
    Key의 경로를 찾아주는 method

    Args:
        key: 읽어온 JSON file에서 불러올 key 값 (깊이 무관)

    Returns:
        `/` 으로 깊이를 표시한 key 값
    """
    keys = self._get_keys()
    if key in keys:
        return key
    if "/" not in key:
        for key_ in keys:
            if key_.endswith(key):
                key = key_
                break
    return key

_get_keys

_get_keys() -> list[str]
Source code in zerohertzLib/util/json.py
def _get_keys(self) -> list[str]:
    if not self.keys and not self.map:
        self.__get_keys(self.data)
    return self.keys

_get_value

_get_value(key: str) -> Any

Json._get_key 로 생성된 key 값을 입력 받아 value return

Parameters:

Name Type Description Default
key str

Json._get_key 로 생성된 key 값

required

Returns:

Type Description
Any

Key에 따른 value

Source code in zerohertzLib/util/json.py
def _get_value(self, key: str) -> Any:
    """
    `Json._get_key` 로 생성된 key 값을 입력 받아 value return

    Args:
        key: `Json._get_key` 로 생성된 key 값

    Returns:
        Key에 따른 value
    """
    value = self.data
    for key_ in key.split("/"):
        if key_ == "LIST":
            value = value[0]
        else:
            value = value.get(key_)
    return value

get

get(key: str) -> Any

Json._get_key 로 생성된 key 값을 입력 받아 value return

Parameters:

Name Type Description Default
key str

읽어온 JSON file에서 불러올 key 값 (깊이 무관)

required

Returns:

Type Description
Any

Key에 따른 value

Examples:

>>> js["title"]
'[v0.2.3] Release'
>>> js.get("title")
'[v0.2.3] Release'
>>> js["color"]
Traceback:
  File "<stdin>", line 1, in <module>
  File "/home/zerohertz/Zerohertz/zerohertzLib/zerohertzLib/util/json.py", line 107, in __getitem__
KeyError: 'color'
>>> js.get("color")
'd73a4a'
Source code in zerohertzLib/util/json.py
def get(self, key: str) -> Any:
    """`Json._get_key` 로 생성된 key 값을 입력 받아 value return

    Args:
        key: 읽어온 JSON file에서 불러올 key 값 (깊이 무관)

    Returns:
        Key에 따른 value

    Examples:
        >>> js["title"]
        '[v0.2.3] Release'
        >>> js.get("title")
        '[v0.2.3] Release'
        >>> js["color"]
        Traceback:
          File "<stdin>", line 1, in <module>
          File "/home/zerohertz/Zerohertz/zerohertzLib/zerohertzLib/util/json.py", line 107, in __getitem__
        KeyError: 'color'
        >>> js.get("color")
        'd73a4a'
    """
    return self._get_value(self._get_key(key))

tree

tree() -> None

JSON의 구조를 출력하는 method

Examples:

>>> js.tree()
├── url
...
├── user
│   ├── login
...
│   └── site_admin
├── body
...
├── assignee
│   ├── login
...
│   └── site_admin
├── assignees
│   └── LIST
│       ├── login
...
│       └── site_admin
...
└── active_lock_reason
Source code in zerohertzLib/util/json.py
def tree(self) -> None:
    """JSON의 구조를 출력하는 method

    Examples:
        >>> js.tree()
        ├── url
        ...
        ├── user
        │   ├── login
        ...
        │   └── site_admin
        ├── body
        ...
        ├── assignee
        │   ├── login
        ...
        │   └── site_admin
        ├── assignees
        │   └── LIST
        │       ├── login
        ...
        │       └── site_admin
        ...
        └── active_lock_reason
    """
    self._get_keys()
    print("\n".join(self.map))

JsonDir

JsonDir(path: str = '')

입력된 경로에 존재하는 JSON 형식 file들을 읽고 사용하기 위한 class

객체 생성 시 path 를 입력하지 않을 시 현재 경로에 존재하는 JSON file들을 읽는다.

Parameters:

Name Type Description Default
path str

JSON file의 경로

''

Attributes:

Name Type Description
name

읽어온 JSON file의 이름들

data

File 이름에 따른 Json 객체 배열

Examples:

>>> jsd = zz.util.JsonDir()
100%|█████████████| 5/5 [00:00<00:00, 3640.26it/s]
>>> len(jsd)
5
>>> jsd[0]
<zerohertzLib.util.json.Json object at 0x7f2562b83d00>
>>> jsd[0]["title"]
'[v0.2.3] Release'
>>> jsd._get_key("color")
'labels/LIST/color'

Methods:

Name Description
__getitem__

Index를 사용하여 JSON file에 접근

__len__

JSON file의 길이를 반환

tree

JSON의 구조를 출력하는 method

unique

읽어온 JSON data들의 유일한 값을 return하는 method

Source code in zerohertzLib/util/json.py
def __init__(self, path: str = "") -> None:
    if path.endswith(".json"):
        raise ValueError("'path' ends with '*.json'")
    self.data = {}
    self.name = []
    for json_path in tqdm(glob(os.path.join(path, "*.json"))):
        name = json_path.replace(path, "").replace("/", "")
        self.data[name] = Json(json_path)
        self.name.append(name)

data instance-attribute

data = {}

name instance-attribute

name = []

__getitem__

__getitem__(idx: int) -> Json

Index를 사용하여 JSON file에 접근

Parameters:

Name Type Description Default
idx int

입력 index

required

Returns:

Type Description
Json

Index에 따른 Json instance

Source code in zerohertzLib/util/json.py
def __getitem__(self, idx: int) -> Json:
    """Index를 사용하여 JSON file에 접근

    Args:
        idx: 입력 index

    Returns:
        Index에 따른 `Json` instance
    """
    return self.data[self.name[idx]]

__len__

__len__() -> int

JSON file의 길이를 반환

Returns:

Type Description
int

읽어온 JSON file들의 수

Source code in zerohertzLib/util/json.py
def __len__(self) -> int:
    """JSON file의 길이를 반환

    Returns:
        읽어온 JSON file들의 수
    """
    return len(self.data)

_get_key

_get_key(key: str) -> str

Key의 경로를 찾아주는 method

Parameters:

Name Type Description Default
key str

읽어온 JSON file에서 불러올 key 값 (깊이 무관)

required

Returns:

Type Description
str

/ 으로 깊이를 표시한 key 값

Source code in zerohertzLib/util/json.py
def _get_key(self, key: str) -> str:
    """
    Key의 경로를 찾아주는 method

    Args:
        key: 읽어온 JSON file에서 불러올 key 값 (깊이 무관)

    Returns:
        `/` 으로 깊이를 표시한 key 값
    """
    return self[0]._get_key(key)

tree

tree() -> None

JSON의 구조를 출력하는 method

Examples:

>>> jsd.tree()
├── url
...
├── user
│   ├── login
...
│   └── site_admin
├── body
...
├── assignee
│   ├── login
...
│   └── site_admin
├── assignees
│   └── LIST
│       ├── login
...
│       └── site_admin
...
└── active_lock_reason
Source code in zerohertzLib/util/json.py
def tree(self) -> None:
    """JSON의 구조를 출력하는 method

    Examples:
        >>> jsd.tree()
        ├── url
        ...
        ├── user
        │   ├── login
        ...
        │   └── site_admin
        ├── body
        ...
        ├── assignee
        │   ├── login
        ...
        │   └── site_admin
        ├── assignees
        │   └── LIST
        │       ├── login
        ...
        │       └── site_admin
        ...
        └── active_lock_reason
    """
    self[0].tree()

unique

unique(key: str) -> set[str]

읽어온 JSON data들의 유일한 값을 return하는 method

Parameters:

Name Type Description Default
key str

읽어온 JSON file에서 불러올 key 값

required

Returns:

Type Description
set[str]

Key에 따른 유일한 값들의 집합

Examples:

>>> jsd.unique("label")
{'Zerohertz:docs', 'Zerohertz:dev-v0.2.3', 'Zerohertz:docs-v0.2.2'}
>>> jsd.unique("sha")
{'dfd53a0bfc73221dbe96d5e44a49c524d5a8596b', 'bc33235424e89cbbf23434b2a824ea068d167c7d', '97f52f9b81ba885fe69b9726632e580f5cba94be', '768c7711f94af0be00cd55e0ce7b892465cfa64a', '97e103788359f0361f4ec0e138a14218f28eddd4'}
Source code in zerohertzLib/util/json.py
def unique(self, key: str) -> set[str]:
    """읽어온 JSON data들의 유일한 값을 return하는 method

    Args:
        key: 읽어온 JSON file에서 불러올 key 값

    Returns:
        Key에 따른 유일한 값들의 집합

    Examples:
        >>> jsd.unique("label")
        {'Zerohertz:docs', 'Zerohertz:dev-v0.2.3', 'Zerohertz:docs-v0.2.2'}
        >>> jsd.unique("sha")
        {'dfd53a0bfc73221dbe96d5e44a49c524d5a8596b', 'bc33235424e89cbbf23434b2a824ea068d167c7d', '97f52f9b81ba885fe69b9726632e580f5cba94be', '768c7711f94af0be00cd55e0ce7b892465cfa64a', '97e103788359f0361f4ec0e138a14218f28eddd4'}
    """
    key = self._get_key(key)
    uniq = set()
    for json_instance in self:
        data = json_instance._get_value(key)
        uniq.add(str(data))
    return uniq

MakeData

MakeData(start_data_path: str, start_json_path: str, json_key: str, target_path: str, end_data_dir: str = 'data', end_json_dir: str = 'json')

Bases: ABC

JSON file 내 값에 따라 data를 구축하는 class

Note

Abstract Base Class: Data 구축 시 filtering 될 조건을 정의하는 abstract method condition 정의 후 사용

Parameters:

Name Type Description Default
start_data_path str

목표 data가 존재하는 directory 경로

required
start_json_path str

목표 JSON file이 존재하는 directory 경로

required
json_key str

start_json 에서 data의 file 이름을 나타내는 key 값

required
target_path str

Data 구축 경로

required
end_data_dir str

구축될 data file들의 directory 이름

'data'
end_json_dir str

구축될 JSON file들의 directory 이름

'json'

Attributes:

Name Type Description
json

JSON file들을 읽어 data 구축 시 활용

end_data_path

{target_path}/{end_data_dir}

end_json_path

{target_path}/{end_json_dir}

Methods:

Name Description
condition

Data 구축 시 filtering 될 조건

make

Data 구축 실행

make_data

Data 구축 방법 정의

Source code in zerohertzLib/util/data.py
def __init__(
    self,
    start_data_path: str,
    start_json_path: str,
    json_key: str,
    target_path: str,
    end_data_dir: str = "data",
    end_json_dir: str = "json",
) -> None:
    self.start_data_path = start_data_path
    self.start_json_path = start_json_path
    self.json = JsonDir(start_json_path)
    self.json_key = self.json._get_key(json_key)
    self.target_path = target_path
    self.end_data_path = os.path.abspath(
        os.path.join(self.target_path, end_data_dir)
    )
    self.end_json_path = os.path.abspath(
        os.path.join(self.target_path, end_json_dir)
    )

end_data_path instance-attribute

end_data_path = abspath(join(target_path, end_data_dir))

end_json_path instance-attribute

end_json_path = abspath(join(target_path, end_json_dir))

json instance-attribute

json = JsonDir(start_json_path)

json_key instance-attribute

json_key = _get_key(json_key)

start_data_path instance-attribute

start_data_path = start_data_path

start_json_path instance-attribute

start_json_path = start_json_path

target_path instance-attribute

target_path = target_path

condition abstractmethod

condition(json_instance: Json) -> bool

Data 구축 시 filtering 될 조건

Parameters:

Name Type Description Default
json_instance Json

Json instance

required

Returns:

Type Description
bool

Data 포함 여부

아래와 같이 상속을 통해 조건을 설정할 수 있다.

Examples:

Condition:

class MakeDataCar(zz.util.MakeData):
    def condition(self, json_instance):
        key = json_instance._get_key("supercategory_name")
        category = json_instance._get_value(key)
        return category == "CityCar" or category == "Mid-size car"

Condition & Make Data:

class MakeDataCarDamage(zz.util.MakeData):
    def condition(self, json_instance):
        annotations = json_instance.get("annotations")
        return (annotations[0]["color"] in ["White", "Black"]) and (
            json_instance.get("supercategory_name") == "CityCar"
        )
    def make_data(self, json_instance, data_name):
        img = cv2.imread(os.path.join(self.start_data_path, data_name))
        for i, ant in enumerate(json_instance["annotations"]):
            label = ant["damage"]
            if not label is None:
                poly = ant["segmentation"]
                poly = np.array(poly[0][0])
                tmp = zz.vision.cutout(img, poly)
                h, w, _ = tmp.shape
                if 100 <= h <= 300 and 100 <= w <= 300:
                    file_name = ".".join(data_name.split(".")[:-1]) + f"_{i}"
                    xm, ym = poly[:, 0].min(), poly[:, 1].min()
                    poly -= (xm, ym)
                    cv2.imwrite(
                        os.path.join(
                            self.end_data_path,
                            f"{file_name}.png",
                        ),
                        tmp,
                    )
                    zz.util.write_json(
                        {"name": f"{file_name}.png", "poly": poly.tolist()},
                        os.path.join(self.end_json_path, file_name),
                    )

Make Data:

class MakeDataCarAugment(zz.util.MakeData):
    def make_data(self, json_instance, data_name):
        img = cv2.imread(
            random.choice(glob("*"))
        )
        target = cv2.imread(
            os.path.join(self.start_data_path, data_name), cv2.IMREAD_UNCHANGED
        )
        H, W, _ = img.shape
        h, w, _ = target.shape
        x, y = random.randrange(100, W - w - 100), random.randrange(100, H - h - 100)
        box = [x, y, x + w, y + h]
        img = zz.vision.paste(img, target, box, False, False)
        file_name = ".".join(data_name.split(".")[:-1])
        cv2.imwrite(
            os.path.join(
                self.end_data_path,
                f"{file_name}.png",
            ),
            img,
        )

Source code in zerohertzLib/util/data.py
@abstractmethod
def condition(self, json_instance: Json) -> bool:
    """Data 구축 시 filtering 될 조건

    Args:
        json_instance: `Json` instance

    Returns:
        Data 포함 여부

    아래와 같이 상속을 통해 조건을 설정할 수 있다.

    Examples:
        Condition:
            ```python
            class MakeDataCar(zz.util.MakeData):
                def condition(self, json_instance):
                    key = json_instance._get_key("supercategory_name")
                    category = json_instance._get_value(key)
                    return category == "CityCar" or category == "Mid-size car"
            ```

        Condition & Make Data:
            ```python
            class MakeDataCarDamage(zz.util.MakeData):
                def condition(self, json_instance):
                    annotations = json_instance.get("annotations")
                    return (annotations[0]["color"] in ["White", "Black"]) and (
                        json_instance.get("supercategory_name") == "CityCar"
                    )
                def make_data(self, json_instance, data_name):
                    img = cv2.imread(os.path.join(self.start_data_path, data_name))
                    for i, ant in enumerate(json_instance["annotations"]):
                        label = ant["damage"]
                        if not label is None:
                            poly = ant["segmentation"]
                            poly = np.array(poly[0][0])
                            tmp = zz.vision.cutout(img, poly)
                            h, w, _ = tmp.shape
                            if 100 <= h <= 300 and 100 <= w <= 300:
                                file_name = ".".join(data_name.split(".")[:-1]) + f"_{i}"
                                xm, ym = poly[:, 0].min(), poly[:, 1].min()
                                poly -= (xm, ym)
                                cv2.imwrite(
                                    os.path.join(
                                        self.end_data_path,
                                        f"{file_name}.png",
                                    ),
                                    tmp,
                                )
                                zz.util.write_json(
                                    {"name": f"{file_name}.png", "poly": poly.tolist()},
                                    os.path.join(self.end_json_path, file_name),
                                )
            ```

        Make Data:
            ```python
            class MakeDataCarAugment(zz.util.MakeData):
                def make_data(self, json_instance, data_name):
                    img = cv2.imread(
                        random.choice(glob("*"))
                    )
                    target = cv2.imread(
                        os.path.join(self.start_data_path, data_name), cv2.IMREAD_UNCHANGED
                    )
                    H, W, _ = img.shape
                    h, w, _ = target.shape
                    x, y = random.randrange(100, W - w - 100), random.randrange(100, H - h - 100)
                    box = [x, y, x + w, y + h]
                    img = zz.vision.paste(img, target, box, False, False)
                    file_name = ".".join(data_name.split(".")[:-1])
                    cv2.imwrite(
                        os.path.join(
                            self.end_data_path,
                            f"{file_name}.png",
                        ),
                        img,
                    )
            ```
    """
    return True

make

make() -> None

Data 구축 실행

.. warning::

실행 시 `target_path` 삭제 후 구축 진행

Examples:

>>> md = MakeData(start_data_path, start_json_path, json_key, target_path)
>>> md.make()
100%|█████████████| 403559/403559 [00:54<00:00, 7369.96it/s]
====================================================================================================
DATA PATH:       /.../data
JSON PATH:       /.../json
====================================================================================================
100%|█████████████| 403559/403559 [01:04<00:00, 6292.39it/s]
Source code in zerohertzLib/util/data.py
def make(self) -> None:
    """Data 구축 실행

    .. warning::

        실행 시 `target_path` 삭제 후 구축 진행

    Examples:
        >>> md = MakeData(start_data_path, start_json_path, json_key, target_path)
        >>> md.make()
        100%|█████████████| 403559/403559 [00:54<00:00, 7369.96it/s]
        ====================================================================================================
        DATA PATH:       /.../data
        JSON PATH:       /.../json
        ====================================================================================================
        100%|█████████████| 403559/403559 [01:04<00:00, 6292.39it/s]
    """
    rmtree(self.target_path)
    print("=" * 100)
    print("DATA PATH:\t", self.end_data_path)
    print("JSON PATH:\t", self.end_json_path)
    print("=" * 100)
    os.makedirs(self.end_data_path, exist_ok=True)
    os.makedirs(self.end_json_path, exist_ok=True)
    for json_instance in tqdm(self.json):
        data_name = json_instance._get_value(self.json_key)
        if self.condition(json_instance):
            self.make_data(json_instance, data_name)

make_data

make_data(json_instance: Json, data_name: str) -> None

Data 구축 방법 정의

Parameters:

Name Type Description Default
json_instance Json

Json instance

required
data_name str

json_key 에 의해 출력된 data의 이름

required

Returns:

Type Description
None

end_data_path, end_json_path 와 본 method를 통해 data 구축

Source code in zerohertzLib/util/data.py
def make_data(self, json_instance: Json, data_name: str) -> None:
    """Data 구축 방법 정의

    Args:
        json_instance: `Json` instance
        data_name: `json_key` 에 의해 출력된 data의 이름

    Returns:
        `end_data_path`, `end_json_path` 와 본 method를 통해 data 구축
    """
    try:
        shutil.copy(
            os.path.join(self.start_data_path, data_name),
            os.path.join(self.end_data_path, data_name),
        )
        shutil.copy(
            os.path.join(self.start_json_path, json_instance.name),
            os.path.join(self.end_json_path, json_instance.name),
        )
    except FileNotFoundError:
        print("Missing:\t", os.path.join(self.start_data_path, data_name))

find_ext

find_ext(path: str = '') -> dict[str, int]

경로 내 확장자의 수 탐색

Parameters:

Name Type Description Default
path str

확장자를 찾을 경로

''

Returns:

Type Description
dict[str, int]

확장자에 따른 file의 수

Examples:

>>> zz.util.find_ext("test/data/")
defaultdict(<class 'int'>, {'test/data/json': 1, 'json': 2, 'jpg': 1, 'mov': 1})
Source code in zerohertzLib/util/data.py
def find_ext(path: str = "") -> dict[str, int]:
    """경로 내 확장자의 수 탐색

    Args:
        path: 확장자를 찾을 경로

    Returns:
        확장자에 따른 file의 수

    Examples:
        >>> zz.util.find_ext("test/data/")
        defaultdict(<class 'int'>, {'test/data/json': 1, 'json': 2, 'jpg': 1, 'mov': 1})
    """
    if not path.endswith("*"):
        path = os.path.join(path, "*")
    file_paths = glob(path)
    exts = defaultdict(int)
    for file_path in file_paths:
        exts[file_path.split(".")[-1]] += 1
    return exts

read_csv

read_csv(path: str, header: bool = True) -> dict[int | str, list[str]]

CSV (Comma-Separated Values) 혹은 TSV (Tab-Separated Values)를 작성하는 function

Parameters:

Name Type Description Default
path str

입력될 CSV 혹은 TSV 경로 및 file 이름

required
header bool

Header의 존재 유무

True

Returns:

Type Description
dict[int | str, list[str]]

Header의 값을 기반으로 column에 따라 list 로 구성

Note

Header가 존재하지 않는 경우 0 부터 차례대로 key 값 정의

Examples:

>>> zz.util.read_csv("star_craft.csv")
defaultdict(<class 'list'>, {'id': ['5hi9', 'gor2', 'gk03'], 'Races': ['Protoss', 'Terran', 'Zerg'], 'Scores': ['1248', '2309', '291']})
>>> zz.util.read_csv("star_craft.tsv")
defaultdict(<class 'list'>, {'id': ['5hi9', 'gor2', 'gk03'], 'Races': ['Protoss', 'Terran', 'Zerg'], 'Scores': ['1248', '2309', '291']})
>>> zz.util.read_csv("star_craft.csv", header=False)
defaultdict(<class 'list'>, {0: ['id', '5hi9', 'gor2', 'gk03'], 1: ['Races', 'Protoss', 'Terran', 'Zerg'], 2: ['Scores', '1248', '2309', '291']})
>>> zz.util.read_csv("star_craft.tsv", header=False)
defaultdict(<class 'list'>, {0: ['id', '5hi9', 'gor2', 'gk03'], 1: ['Races', 'Protoss', 'Terran', 'Zerg'], 2: ['Scores', '1248', '2309', '291']})
Source code in zerohertzLib/util/csv.py
def read_csv(path: str, header: bool = True) -> dict[int | str, list[str]]:
    """CSV (Comma-Separated Values) 혹은 TSV (Tab-Separated Values)를 작성하는 function

    Args:
        path: 입력될 CSV 혹은 TSV 경로 및 file 이름
        header: Header의 존재 유무

    Returns:
        Header의 값을 기반으로 column에 따라 `list` 로 구성

    Note:
        Header가 존재하지 않는 경우 `0` 부터 차례대로 key 값 정의

    Examples:
        >>> zz.util.read_csv("star_craft.csv")
        defaultdict(<class 'list'>, {'id': ['5hi9', 'gor2', 'gk03'], 'Races': ['Protoss', 'Terran', 'Zerg'], 'Scores': ['1248', '2309', '291']})
        >>> zz.util.read_csv("star_craft.tsv")
        defaultdict(<class 'list'>, {'id': ['5hi9', 'gor2', 'gk03'], 'Races': ['Protoss', 'Terran', 'Zerg'], 'Scores': ['1248', '2309', '291']})
        >>> zz.util.read_csv("star_craft.csv", header=False)
        defaultdict(<class 'list'>, {0: ['id', '5hi9', 'gor2', 'gk03'], 1: ['Races', 'Protoss', 'Terran', 'Zerg'], 2: ['Scores', '1248', '2309', '291']})
        >>> zz.util.read_csv("star_craft.tsv", header=False)
        defaultdict(<class 'list'>, {0: ['id', '5hi9', 'gor2', 'gk03'], 1: ['Races', 'Protoss', 'Terran', 'Zerg'], 2: ['Scores', '1248', '2309', '291']})
    """
    data = defaultdict(list)
    keys = []
    with open(path, "r", encoding="utf-8") as file:
        raws = file.readlines()
    if path.endswith(".csv"):
        delimiter = ","
    elif path.endswith(".tsv"):
        delimiter = "\t"
    else:
        raise ValueError("File is not CSV or TSV")
    if header:
        raw = raws[0]
        for key in raw.strip().split(delimiter):
            keys.append(key)
        raws = raws[1:]
    else:
        for key in range(len(raws[0].strip().split(delimiter))):
            keys.append(key)
    for raw in raws:
        for key, value in zip(keys, raw.strip().split(delimiter)):
            data[key].append(value)
    return data

rmtree

rmtree(path: str) -> None

지정한 경로의 file을 삭제하고 다시 생성하는 function

Parameters:

Name Type Description Default
path str

삭제 후 생성할 경로

required

Returns:

Type Description
None

None

Examples:

>>> os.listdir("tmp")
['test']
>>> zz.util.rmtree("tmp")
>>> os.listdir("tmp")
[]
Source code in zerohertzLib/util/data.py
def rmtree(path: str) -> None:
    """지정한 경로의 file을 삭제하고 다시 생성하는 function

    Args:
        path: 삭제 후 생성할 경로

    Returns:
        None

    Examples:
        >>> os.listdir("tmp")
        ['test']
        >>> zz.util.rmtree("tmp")
        >>> os.listdir("tmp")
        []
    """
    try:
        shutil.rmtree(path)
    except FileNotFoundError:
        pass
    os.makedirs(path, exist_ok=True)

sort_dict

sort_dict(target: dict, order: list | None = None) -> dict

Dictionary를 순서에 맞춰 재배열하는 function

Parameters:

Name Type Description Default
target dict

입력 dictionary

required
order list | None

재배열 순서

None

Returns:

Type Description
dict

재배열이 완료된 dictionary

Examples:

>>> zz.util.sort_dict({3: 6, 4: 2, 2: 7})
{2: 7, 3: 6, 4: 2}
>>> zz.util.sort_dict({3: 6, 4: 2, 2: 7}, [4, 2, 3])
{4: 2, 2: 7, 3: 6}
>>> zz.util.sort_dict({"C": 6, "D": 2, "A": 7})
{'A': 7, 'C': 6, 'D': 2}
>>> zz.util.sort_dict({"C": 6, "D": 2, "A": 7}, ["D", "C"])
{'D': 2, 'C': 6}
Source code in zerohertzLib/util/data.py
def sort_dict(target: dict, order: list | None = None) -> dict:
    """Dictionary를 순서에 맞춰 재배열하는 function

    Args:
        target: 입력 dictionary
        order: 재배열 순서

    Returns:
        재배열이 완료된 dictionary

    Examples:
        >>> zz.util.sort_dict({3: 6, 4: 2, 2: 7})
        {2: 7, 3: 6, 4: 2}
        >>> zz.util.sort_dict({3: 6, 4: 2, 2: 7}, [4, 2, 3])
        {4: 2, 2: 7, 3: 6}
        >>> zz.util.sort_dict({"C": 6, "D": 2, "A": 7})
        {'A': 7, 'C': 6, 'D': 2}
        >>> zz.util.sort_dict({"C": 6, "D": 2, "A": 7}, ["D", "C"])
        {'D': 2, 'C': 6}
    """
    if order is None:
        return dict(sorted(target.items()))
    result = {}
    for order_ in order:
        result[order_] = target[order_]
    return result

write_csv

write_csv(data: list[list[Any]], path: str, tsv: bool = False) -> str

CSV (Comma-Separated Values) 혹은 TSV (Tab-Separated Values)를 작성하는 function

Parameters:

Name Type Description Default
data list[list[Any]]

입력 data (header 포함 무관)

required
path str

출력될 CSV 혹은 TSV 경로 및 file 이름

required
tsv bool

TSV 작성 여부

False

Returns:

Type Description
str

File의 절대 경로

Examples:

>>> zz.util.write_csv([["id", "Races", "Scores"], ["5hi9", "Protoss", 1248], ["gor2", "Terran", 2309], ["gk03", "Zerg", 291]], "zerohertzLib/star_craft")
'/.../star_craft.csv'
>>> zz.util.write_csv([["id", "Races", "Scores"], ["5hi9", "Protoss", 1248], ["gor2", "Terran", 2309], ["gk03", "Zerg", 291]], "zerohertzLib/star_craft", True)
'/.../star_craft.tsv'
Source code in zerohertzLib/util/csv.py
def write_csv(data: list[list[Any]], path: str, tsv: bool = False) -> str:
    """CSV (Comma-Separated Values) 혹은 TSV (Tab-Separated Values)를 작성하는 function

    Args:
        data: 입력 data (header 포함 무관)
        path: 출력될 CSV 혹은 TSV 경로 및 file 이름
        tsv: TSV 작성 여부

    Returns:
        File의 절대 경로

    Examples:
        >>> zz.util.write_csv([["id", "Races", "Scores"], ["5hi9", "Protoss", 1248], ["gor2", "Terran", 2309], ["gk03", "Zerg", 291]], "zerohertzLib/star_craft")
        '/.../star_craft.csv'
        >>> zz.util.write_csv([["id", "Races", "Scores"], ["5hi9", "Protoss", 1248], ["gor2", "Terran", 2309], ["gk03", "Zerg", 291]], "zerohertzLib/star_craft", True)
        '/.../star_craft.tsv'
    """
    if tsv:
        with open(f"{path}.tsv", "w", encoding="utf-8") as file:
            for data_ in data:
                file.writelines("\t".join(list(map(str, data_))) + "\n")
        return os.path.abspath(f"{path}.tsv")
    with open(f"{path}.csv", "w", encoding="utf-8") as file:
        for data_ in data:
            file.writelines(",".join(list(map(str, data_))) + "\n")
    return os.path.abspath(f"{path}.csv")

write_json

write_json(data: dict[Any, Any] | list[dict[Any, Any]], path: str) -> str

JSON (JavaScript Object Notation)을 작성하는 function

Parameters:

Name Type Description Default
data dict[Any, Any] | list[dict[Any, Any]]

입력 data (header 포함 무관)

required
path str

출력될 JSON file의 경로 및 이름

required

Returns:

Type Description
str

File의 절대 경로

Examples:

>>> zz.util.write_json([{"id": "4169", "전투력": 4209, "정보": ["아무", "거나"]}]*100, "zerohertzLib/star_craft")
'/.../star_craft.json'
[
    {
        "id": "4169",
        "전투력": 4209,
        "정보": [
            "아무",
            "거나"
        ]
    },
    {
        "id": "4169",
        "전투력": 4209,
        "정보": [
            "아무",
            "거나"
        ]
    },
...
Source code in zerohertzLib/util/json.py
def write_json(data: dict[Any, Any] | list[dict[Any, Any]], path: str) -> str:
    """JSON (JavaScript Object Notation)을 작성하는 function

    Args:
        data: 입력 data (header 포함 무관)
        path: 출력될 JSON file의 경로 및 이름

    Returns:
        File의 절대 경로

    Examples:
        >>> zz.util.write_json([{"id": "4169", "전투력": 4209, "정보": ["아무", "거나"]}]*100, "zerohertzLib/star_craft")
        '/.../star_craft.json'
        [
            {
                "id": "4169",
                "전투력": 4209,
                "정보": [
                    "아무",
                    "거나"
                ]
            },
            {
                "id": "4169",
                "전투력": 4209,
                "정보": [
                    "아무",
                    "거나"
                ]
            },
        ...
    """
    with open(f"{path}.json", "wb") as file:
        file.write(orjson.dumps(data, option=orjson.OPT_INDENT_2))
    return os.path.abspath(f"{path}.json")