import json, re, subprocess, sys DOC = 'https://huggingface.co/docs/transformers/main/en/exporters' EXP = f'`transformers.exporters` ({DOC})' TARGETS = {9784:'issue',12851:'issue',18243:'issue',22221:'issue',22756:'issue',33184:'issue',41838:'issue', 28781:'issue',29288:'issue',31962:'issue',38917:'issue',40260:'issue',29315:'pr'} SUBS = [ # (regex, replacement) applied in order (r'ONNX export (now )?lives in \[Optimum\]\(https://huggingface\.co/docs/optimum/exporters/onnx/overview\)( \(`optimum-cli export onnx --model out/`\))?', f'Export (ONNX included) now goes through [`transformers.exporters`]({DOC})'), (r'ONNX export is now handled by Optimum \(https://huggingface\.co/docs/transformers/main/en/exporters\)', f'export is now handled by {EXP}'), (r'(ONNX )?export (is handled by|now lives in) Optimum( now)?', f'export now goes through {EXP}'), (r'These ONNX exports are used by Transformers\.js / Optimum, so follow-ups belong there\.', f'For exporting, see {EXP}.'), (r'see the wrappers in `src/transformers/integrations/executorch\.py` as noted above, or Optimum for ONNX', f'see {EXP}'), (r'exporting to ONNX \(via Optimum\)', f'exporting to ONNX with {EXP}'), (r'export now goes through torch\.export / optimum', f'export now goes through {EXP}'), (r'For export, `torch\.export` is the recommended path now\.', f'For export, use {EXP}.'), (r'For graph capture, `torch\.export` / `torch\.compile` are the supported paths now\.', f'For export, use {EXP}; `torch.compile` covers graph capture for speed.'), (r'For tracing/export, use `torch\.export` with the static cache', f'For export, use {EXP} with the static cache'), ] POINTER = { 18243: f"The `transformers.onnx` exporter was removed in #41700; export (ONNX included) now goes through {EXP}. Closing; if LongT5 export still fails with `transformers.exporters` on current `main`, please open a new issue with a reproducer.", 22221: f"This isn't a model request: export (ONNX included) now goes through [`transformers.exporters`]({DOC}). To get separate encoders, export `CLIPTextModelWithProjection` and `CLIPVisionModelWithProjection` on their own.", 38917: f"On `main`, the new {EXP} API (#41992) is the recommended way to do this: its exporters take forward kwargs including `past_key_values` (a `Cache`) as example inputs, and there is an ONNX backend in `src/transformers/exporters/exporter_onnx.py`. If something is still missing for your use case, a PR extending the exporters would be very welcome (see https://huggingface.co/docs/transformers/main/en/exporters_extend).", 40260: f"On `main`, export goes through {EXP} (#41992), which supports dynamic shapes; extending it is documented at https://huggingface.co/docs/transformers/main/en/exporters_extend. The legacy helpers in `integrations/executorch.py` are not where new export work should go.", } MARK = re.compile(r'(?i)optimum|torch\.export|executorch') def ours(kind, n): q = '{repository(owner:"huggingface",name:"transformers"){issueOrPullRequest(number:%d){... on Issue{comments(last:40){nodes{databaseId author{login} createdAt body}}} ... on PullRequest{comments(last:40){nodes{databaseId author{login} createdAt body}}}}}}' % n r = json.loads(subprocess.run(['gh','api','graphql','-f','query='+q], capture_output=True, text=True).stdout) return [c for c in r['data']['repository']['issueOrPullRequest']['comments']['nodes'] if (c['author'] or {}).get('login') == 'ArthurZucker' and c['createdAt'] >= '2026-10-20' and MARK.search(c['body'])] plan = [] for n, kind in TARGETS.items(): cs = ours(kind, n) if not cs: print(f'#{n}: NO matching comment of ours'); continue c = cs[-1]; body = c['body'] if n in POINTER: new = POINTER[n] else: new = body for rx, rep in SUBS: new = re.sub(rx, rep, new) if new == body or re.search(r'(?i)optimum', new): print(f'#{n}: UNCHANGED or still mentions optimum →', body[:160].replace('\n',' ')); continue plan.append(dict(n=n, id=c['databaseId'], old=body, new=new)) json.dump(plan, open('exporters_plan.json','w'), indent=1) print('planned edits:', len(plan)) for p in plan: print(f"--- #{p['n']}\n{p['new'][:330]}") if '--apply' in sys.argv: for i, p in enumerate(plan, 1): r = subprocess.run(['gh','api','-X','PATCH',f"repos/huggingface/transformers/issues/comments/{p['id']}",'-f','body='+p['new']], capture_output=True, text=True) print(f"[{i}/{len(plan)}] #{p['n']} {'ok' if r.returncode==0 else 'FAIL '+r.stderr[:120]}", flush=True)