# Path: pytablewriter/_logger/_logger.py
# @property
# def logger(self):
#     return self.__logger
# 
# Path: pytablewriter/sanitizer/_excel.py
# def sanitize_excel_sheet_name(sheet_name: str, replacement_text: str = "") -> str:
#     """
#     Replace invalid characters for an Excel sheet name within
#     the ``sheet_name`` with the ``replacement_text``.
#     Invalid characters are as follows:
#     |invalid_excel_sheet_chars|.
#     The ``sheet_name`` truncate to 31 characters
#     (max sheet name length of Excel) from the head, if the length
#     of the name is exceed 31 characters.
# 
#     :param str sheet_name: Excel sheet name to sanitize.
#     :param str replacement_text: Replacement text.
#     :return: A replacement string.
#     :rtype: str
#     :raises ValueError: If the ``sheet_name`` is an invalid sheet name.
#     """
# 
#     try:
#         unicode_sheet_name = _preprocess(sheet_name)
#     except AttributeError as e:
#         raise ValueError(e)
# 
#     modify_sheet_name = __RE_INVALID_EXCEL_SHEET_NAME.sub(replacement_text, unicode_sheet_name)
# 
#     return modify_sheet_name[:__MAX_SHEET_NAME_LEN]
# 
# Path: pytablewriter/writer/_common.py
# HEADER_ROW = -1
# 
# Path: pytablewriter/writer/_msgfy.py
# def to_error_message(exception_obj: Exception, format_str: Optional[str] = None):
#     if not format_str:
#         format_str = error_message_format
# 
#     frame = inspect.currentframe()
#     if frame is None:
#         return str(exception_obj)
# 
#     return _to_message(exception_obj, format_str, frame.f_back)


import abc
import warnings
import typepy
            import xlwt
            import xlsxwriter
from typing import Any, Dict, Optional
from ..._logger import logger
from ...sanitizer import sanitize_excel_sheet_name
from .._common import import_error_msg_template
from .._msgfy import to_error_message
    def add_worksheet(self, worksheet_name):
        worksheet_name = sanitize_excel_sheet_name(worksheet_name)

        if typepy.is_not_null_string(worksheet_name):
            if worksheet_name in self._worksheet_table:
                # the work sheet is already exists
                return self._worksheet_table.get(worksheet_name)
        else:
            sheet_id = 1
            while True:
                worksheet_name = f"Sheet{sheet_id:d}"
                if worksheet_name not in self._worksheet_table:
                    break
                sheet_id += 1

        worksheet = self.workbook.add_sheet(worksheet_name)
        self._worksheet_table[worksheet_name] = worksheet

        return worksheet


class ExcelWorkbookXlsx(ExcelWorkbook):
    def __init__(self, file_path: str) -> None:
        super().__init__(file_path)

        self.open(file_path)

    def open(self, file_path: str) -> None:
        try:
        except ImportError:

# Path: pytablewriter/_logger/_logger.py
# @property
# def logger(self):
#     return self.__logger
# 
# Path: pytablewriter/sanitizer/_excel.py
# def sanitize_excel_sheet_name(sheet_name: str, replacement_text: str = "") -> str:
#     """
#     Replace invalid characters for an Excel sheet name within
#     the ``sheet_name`` with the ``replacement_text``.
#     Invalid characters are as follows:
#     |invalid_excel_sheet_chars|.
#     The ``sheet_name`` truncate to 31 characters
#     (max sheet name length of Excel) from the head, if the length
#     of the name is exceed 31 characters.
# 
#     :param str sheet_name: Excel sheet name to sanitize.
#     :param str replacement_text: Replacement text.
#     :return: A replacement string.
#     :rtype: str
#     :raises ValueError: If the ``sheet_name`` is an invalid sheet name.
#     """
# 
#     try:
#         unicode_sheet_name = _preprocess(sheet_name)
#     except AttributeError as e:
#         raise ValueError(e)
# 
#     modify_sheet_name = __RE_INVALID_EXCEL_SHEET_NAME.sub(replacement_text, unicode_sheet_name)
# 
#     return modify_sheet_name[:__MAX_SHEET_NAME_LEN]
# 
# Path: pytablewriter/writer/_common.py
# HEADER_ROW = -1
# 
# Path: pytablewriter/writer/_msgfy.py
# def to_error_message(exception_obj: Exception, format_str: Optional[str] = None):
#     if not format_str:
#         format_str = error_message_format
# 
#     frame = inspect.currentframe()
#     if frame is None:
#         return str(exception_obj)
# 
#     return _to_message(exception_obj, format_str, frame.f_back)


# Path: pytablewriter/writer/binary/_excel_workbook.py
import abc
import warnings
import typepy
            import xlwt
            import xlsxwriter
from typing import Any, Dict, Optional
from ..._logger import logger
from ...sanitizer import sanitize_excel_sheet_name
from .._common import import_error_msg_template
from .._msgfy import to_error_message

    def add_worksheet(self, worksheet_name):
        worksheet_name = sanitize_excel_sheet_name(worksheet_name)

        if typepy.is_not_null_string(worksheet_name):
            if worksheet_name in self._worksheet_table:
                # the work sheet is already exists
                return self._worksheet_table.get(worksheet_name)
        else:
            sheet_id = 1
            while True:
                worksheet_name = f"Sheet{sheet_id:d}"
                if worksheet_name not in self._worksheet_table:
                    break
                sheet_id += 1

        worksheet = self.workbook.add_sheet(worksheet_name)
        self._worksheet_table[worksheet_name] = worksheet

        return worksheet


class ExcelWorkbookXlsx(ExcelWorkbook):
    def __init__(self, file_path: str) -> None:
        super().__init__(file_path)

        self.open(file_path)

    def open(self, file_path: str) -> None:
        try:
        except ImportError:

            warnings.warn(import_error_msg_template.format("excel"))