md-table-writer 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thomas Screven
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.4
2
+ Name: md-table-writer
3
+ Version: 0.1.0
4
+ Summary: Generate Markdown formatted tables from data files.
5
+ Author-email: Thomas Screven <tscreven@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/tscreven/MarkdownTableGenerator
8
+ Project-URL: Issues, https://github.com/tscreven/MarkdownTableGenerator/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.12
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: pandas
15
+ Requires-Dist: numpy
16
+ Requires-Dist: openpyxl
17
+ Dynamic: license-file
18
+
19
+ # markdown-table
20
+
21
+ `markdown-table` programatically generates Markdown formatted table(s) from a given data file and writes it to a Markdown file. Supported data file formats: CSV (.csv), NumPy (.npy), and Excel (.xlsx) files.
22
+
23
+ ## Overview
24
+
25
+ Program processes text from data files and processes them into row-ordered table(s) with column headers. The table is written to a Markdown file either at a specific line number or appendeded to the end of the file.
26
+
27
+ **CSV and Excel:** Users have the option to specify which column headers from the file to process. If left unspecified, the package will process all columns. The package assumes the first row in the file is column headers.
28
+
29
+ **Excel**: For Excel files, a new table is generated for every sheet. There is an additional option to specify what sheet names to generate tables for. If left unspecified, every sheet will be processed.
30
+
31
+ **NumPy**: Unlike the other two file types, it is required to specify column headers. The first row in the matrix should not be the intended column headers. The number of column headers must match the number of columns in the matrix.
32
+
33
+
34
+ ## Usage
35
+ ```bash
36
+ markdown-table f md -cols -sheets -align -line -append
37
+ ```
38
+
39
+ | Argument | Description | Required? | Default | Example |
40
+ | :------: | :----------------------------------------------------: | :----------------------------------: | :---------: | :-------------------: |
41
+ | f | Data file | Yes | | data.xlsx |
42
+ | md | Markdown file | Yes | | report.md |
43
+ | -cols | List of column headers to include from data file | No, unless data file is a NumPy file | | -cols Time Population |
44
+ | -sheets | List of sheets from Excel file to write tables for | No | | -sheets Sheet1 Sheet2 |
45
+ | -align | Table column alignment options: left, center, or right | No | center | -align right |
46
+ | -line | Line number in Markdown file to write table to | No | end of file | -line 50 |
47
+ | -append | Flag to write table at end of Markdown file | No | False | -append |
48
+
49
+
50
+ ### Examples
51
+
52
+ ```bash
53
+ markdown-table data.xlsx report.md -cols Time Population -sheets Sheet1 Sheet2 -align right -line 50
54
+ ```
55
+ Generates two tables for Sheet1 and Sheet2 with columns Time and Population from data.xlsx. The table's columns are right aligned. The table is written on line 50 in report.md.
56
+
57
+ ```bash
58
+ markdown-table data.csv report.md -align left -append
59
+ ```
60
+ Generates one table with columns Time and Population from data.csv. The table's columns are left aligned. The table is written to the end of report.md.
61
+
62
+ ```bash
63
+ markdown-table data.npy report.md -cols Time Population -line 50
64
+ ```
65
+ Generates one table from the 2D matrix in data.npy with column headers Time and Population. The table's columns are center aligned. The table is written onen line 50 in report.md.
@@ -0,0 +1,47 @@
1
+ # markdown-table
2
+
3
+ `markdown-table` programatically generates Markdown formatted table(s) from a given data file and writes it to a Markdown file. Supported data file formats: CSV (.csv), NumPy (.npy), and Excel (.xlsx) files.
4
+
5
+ ## Overview
6
+
7
+ Program processes text from data files and processes them into row-ordered table(s) with column headers. The table is written to a Markdown file either at a specific line number or appendeded to the end of the file.
8
+
9
+ **CSV and Excel:** Users have the option to specify which column headers from the file to process. If left unspecified, the package will process all columns. The package assumes the first row in the file is column headers.
10
+
11
+ **Excel**: For Excel files, a new table is generated for every sheet. There is an additional option to specify what sheet names to generate tables for. If left unspecified, every sheet will be processed.
12
+
13
+ **NumPy**: Unlike the other two file types, it is required to specify column headers. The first row in the matrix should not be the intended column headers. The number of column headers must match the number of columns in the matrix.
14
+
15
+
16
+ ## Usage
17
+ ```bash
18
+ markdown-table f md -cols -sheets -align -line -append
19
+ ```
20
+
21
+ | Argument | Description | Required? | Default | Example |
22
+ | :------: | :----------------------------------------------------: | :----------------------------------: | :---------: | :-------------------: |
23
+ | f | Data file | Yes | | data.xlsx |
24
+ | md | Markdown file | Yes | | report.md |
25
+ | -cols | List of column headers to include from data file | No, unless data file is a NumPy file | | -cols Time Population |
26
+ | -sheets | List of sheets from Excel file to write tables for | No | | -sheets Sheet1 Sheet2 |
27
+ | -align | Table column alignment options: left, center, or right | No | center | -align right |
28
+ | -line | Line number in Markdown file to write table to | No | end of file | -line 50 |
29
+ | -append | Flag to write table at end of Markdown file | No | False | -append |
30
+
31
+
32
+ ### Examples
33
+
34
+ ```bash
35
+ markdown-table data.xlsx report.md -cols Time Population -sheets Sheet1 Sheet2 -align right -line 50
36
+ ```
37
+ Generates two tables for Sheet1 and Sheet2 with columns Time and Population from data.xlsx. The table's columns are right aligned. The table is written on line 50 in report.md.
38
+
39
+ ```bash
40
+ markdown-table data.csv report.md -align left -append
41
+ ```
42
+ Generates one table with columns Time and Population from data.csv. The table's columns are left aligned. The table is written to the end of report.md.
43
+
44
+ ```bash
45
+ markdown-table data.npy report.md -cols Time Population -line 50
46
+ ```
47
+ Generates one table from the 2D matrix in data.npy with column headers Time and Population. The table's columns are center aligned. The table is written onen line 50 in report.md.
@@ -0,0 +1,34 @@
1
+ [project]
2
+ name = "md-table-writer"
3
+ version = "0.1.0"
4
+
5
+ authors = [
6
+ { name="Thomas Screven", email="tscreven@gmail.com"}
7
+ ]
8
+ description = "Generate Markdown formatted tables from data files."
9
+ readme = "README.md"
10
+
11
+ dependencies = [
12
+ "pandas",
13
+ "numpy",
14
+ "openpyxl"
15
+ ]
16
+ requires-python = ">=3.12"
17
+ classifiers = [
18
+ "Programming Language :: Python :: 3",
19
+ "Operating System :: OS Independent",
20
+ ]
21
+
22
+ license = "MIT"
23
+ license-files = ["LICENSE"]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/tscreven/MarkdownTableGenerator"
27
+ Issues = "https://github.com/tscreven/MarkdownTableGenerator/issues"
28
+
29
+ [project.scripts]
30
+ markdown-table = "main:main"
31
+
32
+ [tool.setuptools]
33
+ package-dir = {"" = "src"}
34
+ py-modules = ["main", "table_generator"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,36 @@
1
+ import argparse
2
+ from table_generator import MarkdownTable
3
+
4
+ def main():
5
+ parser = argparse.ArgumentParser(
6
+ description="Generate Markdown tables from CSV, Excel, or NumPy files."
7
+ )
8
+ parser.add_argument("f", help="Path to data file.")
9
+ parser.add_argument("md", help="Path to target Markdown file.")
10
+ parser.add_argument("-cols", nargs='+',
11
+ help="Column headers to include from the data file.")
12
+ parser.add_argument("-sheets", nargs='+',
13
+ help="Excel sheet names to generate tables from.")
14
+ parser.add_argument("-align", choices=["left", "center", "right"],
15
+ default="center", help="Table column alignment.")
16
+ parser.add_argument("-line", type=int, default=0,
17
+ help="Line number where table(s) are inserted in the Markdown file.")
18
+ parser.add_argument("-append", action='store_true',
19
+ help="Append table(s) to the end of the Markdown file.")
20
+
21
+ args = parser.parse_args()
22
+
23
+ col_headers = [] if args.cols is None else args.cols
24
+ excel_sheets = [] if args.sheets is None else args.sheets
25
+
26
+ MarkdownTable(args.f,
27
+ args.md,
28
+ args.align,
29
+ args.line,
30
+ args.append,
31
+ col_headers,
32
+ excel_sheets
33
+ )
34
+
35
+ if __name__ == "__main__":
36
+ main()
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.4
2
+ Name: md-table-writer
3
+ Version: 0.1.0
4
+ Summary: Generate Markdown formatted tables from data files.
5
+ Author-email: Thomas Screven <tscreven@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/tscreven/MarkdownTableGenerator
8
+ Project-URL: Issues, https://github.com/tscreven/MarkdownTableGenerator/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.12
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: pandas
15
+ Requires-Dist: numpy
16
+ Requires-Dist: openpyxl
17
+ Dynamic: license-file
18
+
19
+ # markdown-table
20
+
21
+ `markdown-table` programatically generates Markdown formatted table(s) from a given data file and writes it to a Markdown file. Supported data file formats: CSV (.csv), NumPy (.npy), and Excel (.xlsx) files.
22
+
23
+ ## Overview
24
+
25
+ Program processes text from data files and processes them into row-ordered table(s) with column headers. The table is written to a Markdown file either at a specific line number or appendeded to the end of the file.
26
+
27
+ **CSV and Excel:** Users have the option to specify which column headers from the file to process. If left unspecified, the package will process all columns. The package assumes the first row in the file is column headers.
28
+
29
+ **Excel**: For Excel files, a new table is generated for every sheet. There is an additional option to specify what sheet names to generate tables for. If left unspecified, every sheet will be processed.
30
+
31
+ **NumPy**: Unlike the other two file types, it is required to specify column headers. The first row in the matrix should not be the intended column headers. The number of column headers must match the number of columns in the matrix.
32
+
33
+
34
+ ## Usage
35
+ ```bash
36
+ markdown-table f md -cols -sheets -align -line -append
37
+ ```
38
+
39
+ | Argument | Description | Required? | Default | Example |
40
+ | :------: | :----------------------------------------------------: | :----------------------------------: | :---------: | :-------------------: |
41
+ | f | Data file | Yes | | data.xlsx |
42
+ | md | Markdown file | Yes | | report.md |
43
+ | -cols | List of column headers to include from data file | No, unless data file is a NumPy file | | -cols Time Population |
44
+ | -sheets | List of sheets from Excel file to write tables for | No | | -sheets Sheet1 Sheet2 |
45
+ | -align | Table column alignment options: left, center, or right | No | center | -align right |
46
+ | -line | Line number in Markdown file to write table to | No | end of file | -line 50 |
47
+ | -append | Flag to write table at end of Markdown file | No | False | -append |
48
+
49
+
50
+ ### Examples
51
+
52
+ ```bash
53
+ markdown-table data.xlsx report.md -cols Time Population -sheets Sheet1 Sheet2 -align right -line 50
54
+ ```
55
+ Generates two tables for Sheet1 and Sheet2 with columns Time and Population from data.xlsx. The table's columns are right aligned. The table is written on line 50 in report.md.
56
+
57
+ ```bash
58
+ markdown-table data.csv report.md -align left -append
59
+ ```
60
+ Generates one table with columns Time and Population from data.csv. The table's columns are left aligned. The table is written to the end of report.md.
61
+
62
+ ```bash
63
+ markdown-table data.npy report.md -cols Time Population -line 50
64
+ ```
65
+ Generates one table from the 2D matrix in data.npy with column headers Time and Population. The table's columns are center aligned. The table is written onen line 50 in report.md.
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/main.py
5
+ src/table_generator.py
6
+ src/md_table_writer.egg-info/PKG-INFO
7
+ src/md_table_writer.egg-info/SOURCES.txt
8
+ src/md_table_writer.egg-info/dependency_links.txt
9
+ src/md_table_writer.egg-info/entry_points.txt
10
+ src/md_table_writer.egg-info/requires.txt
11
+ src/md_table_writer.egg-info/top_level.txt
12
+ tests/test_table_generator.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ markdown-table = main:main
@@ -0,0 +1,3 @@
1
+ pandas
2
+ numpy
3
+ openpyxl
@@ -0,0 +1,2 @@
1
+ main
2
+ table_generator
@@ -0,0 +1,200 @@
1
+ import pandas as pd
2
+ import sys
3
+ import os
4
+ from typing import Literal
5
+ import numpy as np
6
+
7
+ def error(message:str):
8
+ print(message)
9
+ sys.exit(1)
10
+
11
+ class MarkdownTable:
12
+
13
+ def __init__(self,
14
+ data_file, md_file,
15
+ table_alignment: Literal["left", "center", "right"],
16
+ line_num:int, append:bool, col_headers:list, excel_sheets:list
17
+ ) -> None:
18
+
19
+ if not os.path.exists(data_file):
20
+ error(f"{data_file} does not exist.")
21
+
22
+ if md_file[-3:] != ".md":
23
+ error(f"Target {md_file} is not a Markdown file.")
24
+
25
+ if not os.path.exists(md_file):
26
+ error(f"{md_file} does not exist.")
27
+
28
+ if not append and line_num <= 0:
29
+ print(f"Appending table to end of {md_file} because either no line number was given or the line number is not positive.")
30
+ append = True
31
+
32
+ self.data_file = data_file
33
+ self.md_file = md_file
34
+ self.align = table_alignment
35
+ self.line_num = line_num
36
+ self.append = append
37
+ self.col_headers = col_headers
38
+ self.num_cols = len(col_headers)
39
+
40
+ self.delegate(excel_sheets)
41
+
42
+
43
+ def delegate(self, excel_sheets):
44
+ '''Direct table value processing based on file type.'''
45
+ if self.data_file[-4:] == ".csv":
46
+ self.process_csv()
47
+ elif self.data_file[-4:] == ".npy":
48
+ if self.num_cols == 0:
49
+ error("Column headers must be given for NumPy file.")
50
+ self.process_npy()
51
+ elif self.data_file[-5:] == ".xlsx":
52
+ self.process_excel(excel_sheets)
53
+ else:
54
+ error("Invalid file type. Data file must be either a CSV (.csv), NumPy (.npy), or Excel (.xlsx) file.")
55
+
56
+
57
+ def col_header_update(self, headers):
58
+ '''Update instance for tracking new column headers.'''
59
+ if len(headers) == 0:
60
+ error(f"No column headers given and column headers could not be located in {self.data_file}.")
61
+ self.col_headers = headers
62
+ self.num_cols = len(headers)
63
+
64
+
65
+ def process_dataframe(self, df:pd.DataFrame):
66
+ '''Helper function for file processing functions using Dataframes.'''
67
+
68
+ def check_header(header):
69
+ if header not in df:
70
+ error(f'Category "{header}" is not a column header in {self.data_file}. Note that column headers are case sensitive.')
71
+
72
+ check_header(self.col_headers[0])
73
+
74
+ num_rows = len(df[self.col_headers[0]])
75
+ rows = [[] for _ in range(num_rows)]
76
+
77
+ for header in self.col_headers:
78
+
79
+ check_header(header)
80
+
81
+ if len(df[header]) != num_rows:
82
+ error(f"Unequal column length between columns {self.col_headers[0]} and {header}.")
83
+
84
+ col_values = df[header]
85
+ for i in range(num_rows):
86
+ rows[i].append(col_values[i])
87
+
88
+ self.gen_table(rows)
89
+
90
+
91
+ def process_csv(self):
92
+ '''Process given CSV file: find column headers if none given and store
93
+ values for all tracked column headers in row order.'''
94
+ # If no columns given, assume the entire first row is column headers.
95
+ if self.num_cols == 0:
96
+ with open(self.data_file, 'r') as f:
97
+ line = next(f)
98
+ headers = line.strip().split(',')
99
+ self.col_header_update(headers)
100
+
101
+ df = pd.read_csv(self.data_file)
102
+ self.process_dataframe(df)
103
+
104
+
105
+ def process_excel(self, sheet_names:list):
106
+ '''Process given Excel file: find column headers in sheet_names if none
107
+ are given and store values for all tracked column headers in row order.
108
+ If there are multiple sheets, generate a table for each sheet.'''
109
+
110
+ dfs = pd.read_excel(self.data_file, sheet_name=None)
111
+ all_file_sheets = dfs.keys()
112
+ if sheet_names == []:
113
+ # Load all sheets in Excel file if sheet_names are not specified.
114
+ sheet_names = list(all_file_sheets)
115
+ else:
116
+ for sheet in sheet_names:
117
+ if sheet not in all_file_sheets:
118
+ error(f"Sheet name {sheet} is not in {self.data_file}.")
119
+
120
+ # If no columns given, assume the entire first row is column headers.
121
+ no_headers = self.num_cols == 0
122
+
123
+ for i, sheet in enumerate(sheet_names):
124
+ if no_headers:
125
+ headers = dfs[sheet_names[i]].columns
126
+ self.col_header_update(headers)
127
+
128
+ df = dfs[sheet]
129
+ self.process_dataframe(df)
130
+
131
+
132
+ def process_npy(self):
133
+ '''Process given NumPy file: Column headers must be given. Table values
134
+ are stored in 2D NumPy matrix in row order; transpose the matrix if it
135
+ is required to match the number of expected columns.'''
136
+
137
+ data = np.load(self.data_file)
138
+ assert type(data) == np.ndarray
139
+
140
+ if data.ndim != 2:
141
+ error(f"Invalid number of dimensions in {self.data_file} with {data.ndim} dimension(s). NumPy files must be a 2D matrix.")
142
+
143
+ data_cols = data.shape[1]
144
+ if data_cols != self.num_cols:
145
+ print(f"Mismatch in number of columns in NumPy matrix and given column headers.")
146
+
147
+ if data.shape[0] == self.num_cols:
148
+ print("The number of rows match the number of given column headers. Generated table from transposed matrix.")
149
+ data = data.T
150
+ else:
151
+ error(f"{self.data_file} contains {data_cols} columns, given {self.num_cols} column headers.")
152
+
153
+ self.gen_table(data.tolist())
154
+
155
+
156
+ def gen_table(self, rows:list):
157
+ '''Write Markdown formatted table in md_file at line_num or at end of file.'''
158
+
159
+ next_line = "\n|"
160
+ table_str = next_line
161
+
162
+ # Column headers
163
+ for h in self.col_headers:
164
+ table_str += f" {h} |"
165
+ table_str += next_line
166
+
167
+ if self.align == "left":
168
+ sep = ":-"
169
+ elif self.align == "center":
170
+ sep = ":-:"
171
+ else: # right alignment
172
+ sep = "-:"
173
+
174
+ # Horizontal line separator
175
+ for _ in range(self.num_cols):
176
+ table_str += f" {sep} |"
177
+
178
+ # Add each row
179
+ for row in rows:
180
+ table_str += next_line
181
+ for item in row:
182
+ table_str += f" {item} |"
183
+
184
+ new_lines = len(rows) + 4
185
+
186
+ # Need extra new line for formatting.
187
+ table_str += "\n"*2
188
+
189
+ with open(self.md_file, "r", encoding="utf-8") as f:
190
+ lines = f.readlines()
191
+
192
+ if self.append or self.line_num + 1 > len(lines):
193
+ with open(self.md_file, "a", encoding="utf-8") as f:
194
+ f.write('\n')
195
+ f.write(table_str[:-1])
196
+ new_lines += 1
197
+ else:
198
+ lines.insert(self.line_num - 1, table_str)
199
+ with open(self.md_file, "w", encoding="utf-8") as f:
200
+ f.writelines(lines)
@@ -0,0 +1,122 @@
1
+ import io
2
+ import sys
3
+ import unittest
4
+ from contextlib import redirect_stdout
5
+ from pathlib import Path
6
+ from tempfile import TemporaryDirectory
7
+ import numpy as np
8
+ import pandas as pd
9
+ from typing import Literal
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
12
+
13
+ from table_generator import MarkdownTable
14
+
15
+
16
+ class MarkdownTableTests(unittest.TestCase):
17
+ def setUp(self):
18
+ self.temp_dir = TemporaryDirectory()
19
+ self.base_path = Path(self.temp_dir.name)
20
+ self.md_file = self.base_path / "report.md"
21
+ self.md_file.write_text("# Report\n", encoding="utf-8")
22
+
23
+ def tearDown(self):
24
+ self.temp_dir.cleanup()
25
+
26
+ def generate_table(self, data_file:str, align:Literal["left", "center", "right"]="center",
27
+ line_num=0, append=True, col_headers=[], excel_sheets=[]):
28
+
29
+ MarkdownTable(str(data_file), str(self.md_file), align, line_num,
30
+ append, col_headers, excel_sheets,)
31
+ return self.md_file.read_text(encoding="utf-8")
32
+
33
+
34
+ def test_csv_no_given_headers(self):
35
+ data_file = self.base_path / "data.csv"
36
+ data_file.write_text("Name,Score\nAda,10\nGrace,12\n", encoding="utf-8")
37
+
38
+ content = self.generate_table(str(data_file))
39
+
40
+ self.assertIn(
41
+ "| Name | Score |\n| :-: | :-: |\n| Ada | 10 |\n| Grace | 12 |",
42
+ content,
43
+ )
44
+
45
+
46
+ def test_csv_with_given_headers(self):
47
+ data_file = self.base_path / "data.csv"
48
+ data_file.write_text("Name,Score,Rank\nAda,10,2\nGrace,12,1\n", encoding="utf-8")
49
+
50
+ content = self.generate_table(str(data_file), align="right", col_headers=["Rank", "Name"])
51
+
52
+ self.assertIn( "| Rank | Name |\n| -: | -: |\n| 2 | Ada |\n| 1 | Grace |", content)
53
+
54
+
55
+ def test_line_insertion(self):
56
+ self.md_file.write_text("First\nSecond\nThird\n", encoding="utf-8")
57
+ data_file = self.base_path / "data.csv"
58
+ data_file.write_text("Name,Score\nAda,10\n", encoding="utf-8")
59
+
60
+ content = self.generate_table( str(data_file), align="left", line_num=2,
61
+ append=False, col_headers=["Name", "Score"])
62
+
63
+ self.assertTrue(content.startswith("First\n\n| Name | Score |"))
64
+ self.assertIn("| :- | :- |\n| Ada | 10 |", content)
65
+ self.assertTrue(content.endswith("\nSecond\nThird\n"))
66
+
67
+ def test_np_array(self):
68
+ data_file = self.base_path / "data.npy"
69
+ np.save(data_file, np.array([[1, 2], [3, 4]]))
70
+
71
+ content = self.generate_table(str(data_file), col_headers=["A", "B"])
72
+
73
+ self.assertIn("| A | B |\n| :-: | :-: |\n| 1 | 2 |\n| 3 | 4 |", content)
74
+
75
+ def test_np_array_transposed(self):
76
+ data_file = self.base_path / "data.npy"
77
+ np.save(data_file, np.array([[1, 2, 3], [4, 5, 6]]))
78
+
79
+ with redirect_stdout(io.StringIO()):
80
+ content = self.generate_table(str(data_file), col_headers=["A", "B"])
81
+
82
+ self.assertIn("| A | B |\n| :-: | :-: |\n| 1 | 4 |\n| 2 | 5 |\n| 3 | 6 |", content)
83
+
84
+ def test_excel_given_sheets_headers(self):
85
+ data_file = self.base_path / "data.xlsx"
86
+ with pd.ExcelWriter(data_file) as writer:
87
+ pd.DataFrame({"Name": ["Ada"], "Score": [10]}).to_excel(
88
+ writer, sheet_name="Scores", index=False
89
+ )
90
+ pd.DataFrame({"Name": ["Ignored"], "Score": [0]}).to_excel(
91
+ writer, sheet_name="Other", index=False
92
+ )
93
+
94
+ content = self.generate_table(str(data_file), col_headers=["Name", "Score"], excel_sheets=["Scores"])
95
+
96
+ self.assertIn("| Name | Score |\n| :-: | :-: |\n| Ada | 10 |", content)
97
+ self.assertNotIn("Ignored", content)
98
+
99
+ def test_np_array_no_headers_assert_error(self):
100
+ data_file = self.base_path / "data.npy"
101
+ np.save(data_file, np.array([[1]]))
102
+
103
+ with self.assertRaises(SystemExit) as raised, redirect_stdout(io.StringIO()) as output:
104
+ MarkdownTable(str(data_file), str(self.md_file), "center", 0, True, [], [])
105
+
106
+ self.assertEqual(raised.exception.code, 1)
107
+ self.assertIn("Column headers must be given for NumPy file.", output.getvalue())
108
+
109
+
110
+ def test_given_wrong_header_assert_error(self):
111
+ data_file = self.base_path / "data.csv"
112
+ data_file.write_text("Name,Score\nAda,10\n", encoding="utf-8")
113
+
114
+ with self.assertRaises(SystemExit) as raised, redirect_stdout(io.StringIO()) as output:
115
+ MarkdownTable(str(data_file), str(self.md_file), "center", 0, True, ["Missing"], [])
116
+
117
+ self.assertEqual(raised.exception.code, 1)
118
+ self.assertIn( 'Category "Missing" is not a column header in', output.getvalue())
119
+
120
+
121
+ if __name__ == "__main__":
122
+ unittest.main()