Skip to content

Commit 4c84f4f

Browse files
authored
Remove tabulate from CI tests and migrate regex to pcre (#2787)
* Remove tabulate from CI tests and migrate regex to pcre * Run formatter and fix HF compat import
1 parent 5c7fd20 commit 4c84f4f

33 files changed

Lines changed: 196 additions & 82 deletions

.github/scripts/ci_deps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import argparse
2-
import re
32
import subprocess
43
import sys
54
from pathlib import Path
65
from typing import Any
76

7+
import pcre
88
import yaml
99

1010
BASE_DIR = Path(__file__).resolve().parent
11-
_PKG_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]+")
11+
_PKG_NAME_RE = pcre.compile(r"^[A-Za-z0-9_.-]+")
1212

1313

1414
def resolve_test_path(raw_name: str) -> Path:

.github/scripts/ci_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import argparse
22
import os
3-
import re
43
import signal
54
import subprocess
65
import sys
@@ -9,14 +8,15 @@
98
import urllib.error
109
from pathlib import Path
1110

11+
import pcre
1212
from ci_gpu import (
1313
build_job_request,
1414
extract_gpu_ids,
1515
normalize_base_url,
1616
request_json,
1717
)
1818

19-
ERROR_PATTERN = re.compile(
19+
ERROR_PATTERN = pcre.compile(
2020
r"nvcc fatal|error:|fatal error|ModuleNotFoundError|ImportError|AssertionError|Exception|is the correct path|No such file or directory|Repo id must be in"
2121
)
2222

.github/scripts/ci_workflow.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import argparse
22
import json
33
import os
4-
import re
54
import shlex
65
import sys
76
from pathlib import Path
87
from pathlib import PurePosixPath
98
from typing import Any
109

10+
import pcre
1111
import requests
1212
import yaml
1313
from packaging.specifiers import SpecifierSet
@@ -129,9 +129,9 @@ def is_model_compat_test(rel_path: str, file_path: Path) -> bool:
129129

130130

131131
def matches_test_regex(test_regex: str, rel_path: str) -> bool:
132-
if re.match(test_regex, rel_path):
132+
if pcre.match(test_regex, rel_path):
133133
return True
134-
return re.match(test_regex, PurePosixPath(rel_path).name) is not None
134+
return pcre.match(test_regex, PurePosixPath(rel_path).name) is not None
135135

136136

137137
def should_skip_test(yaml_file: str | Path, rel_path: str) -> bool:

.github/scripts/deps.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
common:
22
- tokenicer
33
- transformers
4-
- tabulate
54
- swig # for models/tests
65

76
tests:

gptqmodel/exllamav3/util/memory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def list_gpu_tensors(min_size: int = 1, cuda_only: bool = True):
7272

7373
import threading
7474
import warnings
75-
from tabulate import tabulate
75+
from ...utils.logger import render_table
7676

7777
# Suppress FutureWarning from Torch every time we try to access certain objects
7878
warnings.simplefilter(action = 'ignore', category = FutureWarning)
@@ -225,4 +225,4 @@ def collect(path, item):
225225
print("--------------")
226226
print()
227227
headers = ["size // MB", "path", "shape", "dtype"]
228-
print(tabulate(devices[k], headers = headers, tablefmt = "github", intfmt=","))
228+
print(render_table(devices[k], headers=headers, tablefmt="github"))

gptqmodel/quantization/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
from ..adapter.adapter import Lora, normalize_adapter
2525
from ..utils.logger import setup_logger
26+
27+
2628
log = setup_logger()
2729

2830

gptqmodel/utils/cpp.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import logging
1010
import math
1111
import os
12-
import re
1312
import shutil
1413
import subprocess
1514
import sys
@@ -373,7 +372,7 @@ def cuda_include_paths_with_fallback(
373372
return _dedupe_path_strings(resolved_include_paths)
374373

375374

376-
_CUDA_ARCH_TOKEN_RE = re.compile(r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\+PTX)?$")
375+
_CUDA_ARCH_TOKEN_RE = pcre.compile(r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\+PTX)?$")
377376

378377

379378
def _supported_cuda_arch_pairs() -> list[tuple[int, int]]:
@@ -413,7 +412,7 @@ def _visible_cuda_arch_tokens() -> list[str]:
413412
def _merge_cuda_arch_override_with_visible_caps(raw_override: str) -> str:
414413
requested_tokens: list[str] = []
415414
requested_bases: set[str] = set()
416-
for token in re.split(r"[;\s,]+", raw_override.strip()):
415+
for token in pcre.split(r"[;\s,]+", raw_override.strip()):
417416
if not token:
418417
continue
419418
requested_tokens.append(token)

gptqmodel/utils/hf.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616
import torch
1717
import transformers
1818
from accelerate import init_empty_weights
19-
from transformers import AutoConfig, AutoModelForCausalLM, GenerationConfig, PreTrainedModel
19+
from transformers import (
20+
AutoConfig,
21+
AutoModelForCausalLM,
22+
GenerationConfig,
23+
PreTrainedConfig,
24+
PreTrainedModel,
25+
)
2026

2127
from ..nn_modules.qlinear.gguf import (
2228
PRISM_Q1_0_G128_BLOCK_SIZE,

gptqmodel/utils/logger.py

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@
44
# Contact: qubitium@modelcloud.ai, x.com/qubitium
55

66
import contextlib
7+
import numbers
78
import os
89
import sys
910
import threading
1011
import time
1112
from collections import OrderedDict
12-
from typing import Dict, Iterator, Optional
13+
from typing import Any, Dict, Iterator, Optional, Sequence
1314

15+
import pcre
1416
from logbar import LogBar
1517

1618

19+
_ANSI_ESCAPE_RE = pcre.compile(r"\x1b\[[0-9;]*m")
20+
21+
1722
class _SilentProgress:
1823
"""Minimal no-op progress handle for non-interactive test sessions."""
1924

@@ -102,6 +107,99 @@ def setup_logger():
102107
return _AdaptiveLoggerProxy(LogBar.shared())
103108

104109

110+
def _table_cell_text(value: Any, floatfmt: Optional[str]) -> str:
111+
if value is None:
112+
return ""
113+
if isinstance(value, bool):
114+
return str(value)
115+
if floatfmt is not None and isinstance(value, numbers.Real) and not isinstance(value, numbers.Integral):
116+
return format(float(value), floatfmt)
117+
return str(value)
118+
119+
120+
def _visible_width(value: str) -> int:
121+
return len(_ANSI_ESCAPE_RE.sub("", value))
122+
123+
124+
def _pad_table_cell(value: str, width: int) -> str:
125+
return value + (" " * max(0, width - _visible_width(value)))
126+
127+
128+
def _render_grid_table(headers: Sequence[str], rows: Sequence[Sequence[str]], widths: Sequence[int]) -> str:
129+
def border() -> str:
130+
return "+" + "+".join("-" * (width + 2) for width in widths) + "+"
131+
132+
def row_line(values: Sequence[str]) -> str:
133+
return "| " + " | ".join(_pad_table_cell(value, widths[idx]) for idx, value in enumerate(values)) + " |"
134+
135+
lines = [border(), row_line(headers), border()]
136+
lines.extend(row_line(row) for row in rows)
137+
lines.append(border())
138+
return "\n".join(lines)
139+
140+
141+
def _render_github_table(headers: Sequence[str], rows: Sequence[Sequence[str]], widths: Sequence[int]) -> str:
142+
def row_line(values: Sequence[str]) -> str:
143+
return "| " + " | ".join(_pad_table_cell(value, widths[idx]) for idx, value in enumerate(values)) + " |"
144+
145+
separator = "| " + " | ".join("-" * width for width in widths) + " |"
146+
lines = [row_line(headers), separator]
147+
lines.extend(row_line(row) for row in rows)
148+
return "\n".join(lines)
149+
150+
151+
def _render_simple_table(headers: Sequence[str], rows: Sequence[Sequence[str]], widths: Sequence[int]) -> str:
152+
def row_line(values: Sequence[str]) -> str:
153+
return " ".join(_pad_table_cell(value, widths[idx]) for idx, value in enumerate(values))
154+
155+
separator = " ".join("-" * width for width in widths)
156+
lines = [row_line(headers), separator]
157+
lines.extend(row_line(row) for row in rows)
158+
return "\n".join(lines)
159+
160+
161+
def render_table(
162+
rows: Sequence[Sequence[Any]],
163+
*,
164+
headers: Sequence[Any],
165+
tablefmt: str = "grid",
166+
floatfmt: Optional[str] = None,
167+
logger: Optional[LogBar] = None,
168+
) -> str:
169+
"""Render a small diagnostic table using LogBar-compatible column sizing."""
170+
171+
header_text = [str(header) for header in headers]
172+
row_text: list[list[str]] = []
173+
for row in rows:
174+
values = list(row)
175+
if len(values) != len(header_text):
176+
raise ValueError(
177+
f"Row length {len(values)} does not match header length {len(header_text)}"
178+
)
179+
row_text.append([_table_cell_text(value, floatfmt) for value in values])
180+
181+
widths = [_visible_width(header) for header in header_text]
182+
if header_text:
183+
columns = (logger or LogBar.shared()).columns(
184+
cols=[{"label": header, "width": "fit"} for header in header_text],
185+
padding=1,
186+
)
187+
for row in row_text:
188+
columns.info.simulate(*row)
189+
widths = [max(widths[idx], width) for idx, width in enumerate(columns.widths)]
190+
191+
for row in row_text:
192+
for idx, cell in enumerate(row):
193+
widths[idx] = max(widths[idx], _visible_width(cell))
194+
195+
tablefmt_normalized = (tablefmt or "grid").lower()
196+
if tablefmt_normalized == "github":
197+
return _render_github_table(header_text, row_text, widths)
198+
if tablefmt_normalized == "simple":
199+
return _render_simple_table(header_text, row_text, widths)
200+
return _render_grid_table(header_text, row_text, widths)
201+
202+
105203
class QuantizationRegionTimer:
106204
"""Aggregate and display timing statistics for key quantization stages."""
107205

gptqmodel/utils/paroquant_benchmark.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
from typing import Any, Optional
1212

1313
import torch
14-
from tabulate import tabulate
1514

1615
from gptqmodel import GPTQModel
1716
from gptqmodel.nn_modules.qlinear.paroquant import ParoLinear
1817
from gptqmodel.nn_modules.qlinear.paroquant_triton import ParoQuantTritonLinear
1918
from gptqmodel.quantization import FORMAT, METHOD
2019
from gptqmodel.quantization.config import QuantizeConfig
2120
from gptqmodel.utils.backend import BACKEND
21+
from gptqmodel.utils.logger import render_table
2222

2323

2424
_NM_CALIBRATION_PATH = "/monster/data/model/dataset/nm-calibration"
@@ -868,22 +868,22 @@ def comparison_rows(*cases: dict[str, Any]) -> list[list[str]]:
868868

869869
def render_case_tables(case: dict[str, Any]) -> dict[str, str]:
870870
return {
871-
"comparison": tabulate(
871+
"comparison": render_table(
872872
comparison_rows(case),
873873
headers=["case", "opt_scope", "sym", "fused_opt", "gsm8k_platinum_cot", "quant_wall_s", "eval_wall_s"],
874874
tablefmt="grid",
875875
),
876-
"module_times": tabulate(
876+
"module_times": render_table(
877877
case.get("module_time_rows", []),
878878
headers=["layer", "module", "feat", "samples", "loss", "time_s"],
879879
tablefmt="grid",
880880
),
881-
"regions": tabulate(
881+
"regions": render_table(
882882
case.get("region_rows", []),
883883
headers=["region", "count", "last_s", "avg_s", "total_s", "pct", "source"],
884884
tablefmt="grid",
885885
),
886-
"kernels": tabulate(
886+
"kernels": render_table(
887887
case.get("kernel_rows", []),
888888
headers=[
889889
"module",

0 commit comments

Comments
 (0)