xlsx-to-tsv/xlsx_to_tsv/__init__.py

83 lines
1.9 KiB
Python

# /// script
# dependencies = [
# "openpyxl",
# ]
# ///
import sys
from pathlib import Path
from openpyxl import load_workbook
from openpyxl.workbook.workbook import Workbook
from openpyxl.worksheet.worksheet import Worksheet
def _get_worksheet(wb: Workbook, sheet: str | int | None) -> Worksheet:
if sheet is None:
return wb.active
if isinstance(sheet, int):
return wb.worksheets[sheet]
return wb[sheet]
def xlsx_to_tsv(
input_path: Path,
output_path: Path,
*,
sheet: str | int | None = None,
) -> None:
wb = load_workbook(input_path, read_only=True, data_only=True)
try:
ws = _get_worksheet(wb, sheet)
with output_path.open('w', encoding='utf-8', newline='') as f:
for row in ws.iter_rows(values_only=True):
values = ['' if v is None else str(v) for v in row]
f.write('\t'.join(values) + '\n')
finally:
wb.close()
def _parse_sheet(value: str) -> str | int:
try:
return int(value)
except ValueError:
return value
_usage_str = """\
Usage:
xlsx_to_tsv.py INPUT OUTPUT [SHEET]
Arguments:
INPUT Input .xlsx file path
OUTPUT Output .tsv file path
SHEET Optional worksheet name or zero-based index
By default, the active worksheet is exported to TSV format.
"""
def main(argv: list[str] | None = None) -> int:
args = sys.argv[1:] if argv is None else argv
if not args or args[0] in {'-h', '--help'}:
print(_usage_str, end='') # noqa: T201
return 0
if len(args) not in {2, 3}:
print(_usage_str, end='', file=sys.stderr) # noqa: T201
return 2
input_path = Path(args[0])
output_path = Path(args[1])
sheet = _parse_sheet(args[2]) if len(args) == 3 else None # noqa: PLR2004
xlsx_to_tsv(input_path, output_path, sheet=sheet)
return 0
if __name__ == '__main__':
raise SystemExit(main())