|
37 | 37 |
|
38 | 38 | import httpx |
39 | 39 | import packaging.version |
40 | | -import tabulate |
41 | 40 | import wcwidth |
42 | 41 | from tqdm import tqdm |
43 | 42 |
|
|
46 | 45 |
|
47 | 46 | _FILE_HEAD = """# Plugin List |
48 | 47 |
|
49 | | -PyPI projects that match `pytask-*` are considered plugins and are listed |
50 | | -automatically. Packages classified as inactive are excluded. |
| 48 | +PyPI projects that match `pytask-*` are considered plugins and are listed automatically. |
| 49 | +Packages classified as inactive are excluded. |
51 | 50 |
|
52 | 51 | !!! warning |
53 | 52 |
|
54 | | - Please be aware that this list is not a curated collection of projects and does not |
55 | | - undergo a systematic review process. It serves purely as an informational resource |
56 | | - to aid in the discovery of `pytask` plugins. |
| 53 | +``` |
| 54 | +Please be aware that this list is not a curated collection of projects and does not |
| 55 | +undergo a systematic review process. It serves purely as an informational resource |
| 56 | +to aid in the discovery of `pytask` plugins. |
57 | 57 |
|
58 | | - Do not presume any endorsement from the `pytask` project or its developers, and |
59 | | - always conduct your own quality assessment before incorporating any of these plugins |
60 | | - into your own projects. |
| 58 | +Do not presume any endorsement from the `pytask` project or its developers, and |
| 59 | +always conduct your own quality assessment before incorporating any of these plugins |
| 60 | +into your own projects. |
| 61 | +``` |
61 | 62 |
|
62 | 63 | """ |
63 | 64 |
|
@@ -86,6 +87,43 @@ def _escape_markdown(text: str) -> str: |
86 | 87 | return text.replace("|", "\\|") |
87 | 88 |
|
88 | 89 |
|
| 90 | +def _pad(text: str, width: int) -> str: |
| 91 | + """Pad text to the requested display width.""" |
| 92 | + return text + " " * (width - wcwidth.wcswidth(text)) |
| 93 | + |
| 94 | + |
| 95 | +def _create_table(entries: list[dict[str, str]]) -> str: |
| 96 | + """Create a markdown table in the repository's canonical format.""" |
| 97 | + if not entries: |
| 98 | + msg = "Cannot create a plugin table without entries." |
| 99 | + raise ValueError(msg) |
| 100 | + |
| 101 | + headers = list(entries[0]) |
| 102 | + widths = [ |
| 103 | + max( |
| 104 | + wcwidth.wcswidth(header), |
| 105 | + *(wcwidth.wcswidth(row[header]) for row in entries), |
| 106 | + ) |
| 107 | + for header in headers |
| 108 | + ] |
| 109 | + |
| 110 | + header_cells = ( |
| 111 | + _pad(header, width) for header, width in zip(headers, widths, strict=False) |
| 112 | + ) |
| 113 | + header = "| " + " | ".join(header_cells) + " |" |
| 114 | + separator = "| " + " | ".join("-" * width for width in widths) + " |" |
| 115 | + rows = [ |
| 116 | + "| " |
| 117 | + + " | ".join( |
| 118 | + _pad(row[header], width) |
| 119 | + for header, width in zip(headers, widths, strict=False) |
| 120 | + ) |
| 121 | + + " |" |
| 122 | + for row in entries |
| 123 | + ] |
| 124 | + return "\n".join([header, separator, *rows]) |
| 125 | + |
| 126 | + |
89 | 127 | def _iter_plugins() -> Generator[dict[str, str], None, None]: # noqa: C901 |
90 | 128 | """Iterate over all plugins and format entries.""" |
91 | 129 | regex = r">([\d\w-]*)</a>" |
@@ -168,10 +206,7 @@ def main() -> None: |
168 | 206 | with plugin_list.open("w") as f: |
169 | 207 | f.write(_FILE_HEAD) |
170 | 208 | f.write(f"This list contains {len(plugins)} plugins.\n\n") |
171 | | - |
172 | | - assert wcwidth # reference library that must exist for tabulate to work |
173 | | - plugin_table = tabulate.tabulate(plugins, headers="keys", tablefmt="github") |
174 | | - f.write(plugin_table) |
| 209 | + f.write(_create_table(plugins)) |
175 | 210 | f.write("\n") |
176 | 211 |
|
177 | 212 |
|
|
0 commit comments