Error Suppressing with DevNull of Python (+Python Lock)

Python DevNull class 만들기
May 29, 2024
Error Suppressing with DevNull of Python (+Python Lock)

Python console 관리를 위한 custom DevNull class

error suppressing DevNull class example

사용 계기는 다음과 같다.

binetrees package에서 class들을 사용하는데, C를 사용해 compile된 binetrees가

python trees를 사용한다며 error를 실행부에 맨 윗줄에 반환하여

error를 suppress하고자 sys.stderr에 DevNull() object를 assign해 주었다.

import threading
import sys
import os
from bintrees import BinaryTree, AVLTree
from threading import Lock

# Lock to ensure thread-safe output
print_lock = Lock()

def inorder(tree):
    return [key for key in tree.keys()]

def preorder(tree):
    result = []

    def _preorder(node):
        if node:
            result.append(node.key)
            _preorder(node.left)
            _preorder(node.right)

    _preorder(tree._root)
    return result

def postorder(tree):
    result = []

    def _postorder(node):
        if node:
            _postorder(node.left)
            _postorder(node.right)
            result.append(node.key)

    _postorder(tree._root)
    return result

class TreeFormatter:
    @staticmethod
    def get_traversal_sequences(tree):
        if isinstance(tree, BinaryTree) or isinstance(tree, AVLTree):
            in_order_seq = inorder(tree)
            pre_order_seq = preorder(tree)
            post_order_seq = postorder(tree)
            return in_order_seq, pre_order_seq, post_order_seq
        else:
            raise ValueError("Tree object must be of type BinaryTree or AVLTree")

    @staticmethod
    def format_box(in_order_seq, pre_order_seq, post_order_seq):
        max_length = max(len(in_order_seq), len(pre_order_seq), len(post_order_seq))
        in_order_seq += [''] * (max_length - len(in_order_seq))
        pre_order_seq += [''] * (max_length - len(pre_order_seq))
        post_order_seq += [''] * (max_length - len(post_order_seq))
        return in_order_seq, pre_order_seq, post_order_seq

    @staticmethod
    def print_box(in_order_seq, pre_order_seq, post_order_seq):
        in_order_seq, pre_order_seq, post_order_seq = TreeFormatter.format_box(in_order_seq, pre_order_seq, post_order_seq)
        with print_lock:
            print("In-order:   ", " ".join(map(str, in_order_seq)), flush=True)
            print("Pre-order:  ", " ".join(map(str, pre_order_seq)), flush=True)
            print("Post-order: ", " ".join(map(str, post_order_seq)), flush=True)

def process_tree(tree, insert_sequence, delete_sequence, operation_type, step):
    with print_lock:
        print(f"{step}. {operation_type}")
    
    # Insert elements into the tree
    for num in insert_sequence:
        tree.insert(num, None)

    # Print insertion results
    in_order_seq, pre_order_seq, post_order_seq = TreeFormatter.get_traversal_sequences(tree)
    TreeFormatter.print_box(in_order_seq, pre_order_seq, post_order_seq)

    with print_lock:
        print()
        print(f"{step+1}. {operation_type.replace('Insertion', 'Deletion')}")

    # Delete elements from the tree
    for num in delete_sequence:
        tree.remove(num)

    # Print deletion results
    in_order_seq, pre_order_seq, post_order_seq = TreeFormatter.get_traversal_sequences(tree)
    TreeFormatter.print_box(in_order_seq, pre_order_seq, post_order_seq)

def suppress_warnings():
    class DevNull:
        def write(self, msg):
            pass

    sys.stderr = DevNull()

def main():
    suppress_warnings()

    insert_sequence = [5, 3, 7, 8, 2, 9, 1]
    delete_sequence = [1, 2, 5, 8, 9]

    btree = BinaryTree()
    avltree = AVLTree()

    print(">>>소프트웨어공학과")

    process_tree(btree, insert_sequence, delete_sequence, "Binary Tree Insertion", 1)
    print()
    process_tree(avltree, insert_sequence, delete_sequence, "AVL Tree Insertion", 3)

if __name__ == "__main__":
    main()

Python threading library의 Lock final class(py3.12.3 doc for threading)가 할당받는 _allocate_lock ~ thread.py - allocate_lock() function 으로

thread를 safe하게 처리하는 lock에 대해서도 간단하게 정리하겠다.

(예시로 작성한 library 내 감싸인 object들은 pyi file에(설명) 작성돼 있거나 python document만 남아 있는 경우가 많다)

상위 코드에서는 print 라인의 number가 많아졌을 때를 대비하였다.

순차적으로 buffered state의 종료 이전에 즉각적으로 line들의 output을 순차적으로 print할 수 있도록, flush=true에 추가로 lock을 사용하였다.

Share article

SW Engineering Blog