Skip to content

feat(mypyc): Enable incremental compilation#7558

Open
VaggelisD wants to merge 1 commit intomainfrom
mypyc-separate-flag
Open

feat(mypyc): Enable incremental compilation#7558
VaggelisD wants to merge 1 commit intomainfrom
mypyc-separate-flag

Conversation

@VaggelisD
Copy link
Copy Markdown
Collaborator

@VaggelisD VaggelisD commented Apr 24, 2026

What

Switch sqlglotc's mypyc build to separate=True, plus the two small sqlglot-side tweaks needed to make it work end-to-end.

The separate=True flag gives each compiled module its own shared lib + shim, so mypyc only has to regenerate / recompile the modules whose source actually changed. Clean builds are roughly the same wall-clock; incremental rebuilds after a one-line edit drop dramatically once the cache is warm.

Three small changes, all behind the [c] compile path:

  • sqlglotc/setup.py: pass separate=True to mypycify(). Everything else in the build recipe is unchanged.
  • sqlglot/__init__.py: the existing *__mypyc*.so bootstrap preloader was written for the old monolithic build where a single hash-named .so sat at the package root. Under separate=True the per-module shared libs (e.g. errors__mypyc.so) live next to their .py siblings and resolve through Python's normal import machinery via the shim. Skip preloading those; keep the legacy behavior only for .so files that don't have a .py sibling.
  • sqlglot/optimizer/__init__.py: swap the eager top-level re-exports for PEP 562 lazy __getattr__. Under separate=True's cross-group init ordering, the previous eager from sqlglot.optimizer.optimizer import ... could fire while sqlglot's own __init__.py was still mid-bootstrap, hitting a circular-import ImportError on from sqlglot import Schema, exp. Lazy imports defer the cycle to first use.

@VaggelisD VaggelisD changed the title feat(mypyc): enable separate=True for faster incremental compilation [CLAUDE] feat(mypyc): Enable incremental compilation Apr 24, 2026
@VaggelisD VaggelisD force-pushed the mypyc-separate-flag branch from 071ea34 to 8db1da4 Compare April 24, 2026 13:38
…[CLAUDE]

sqlglot-mypy 1.20.0.post3 makes mypyc's separate=True compilation work
correctly on real-world projects (cross-group class inheritance, generator
helper classes, non-ext subclasses with fast methods, mutually-dependent
compiled modules). Turning it on for sqlglotc cuts incremental rebuild
time dramatically — a 1-file edit goes from ~110s (full monolithic rebuild)
to ~3s.

Three small changes:

- sqlglotc/setup.py: pass separate=True to mypycify(). Produces one
  shared lib + shim pair per module instead of one monolithic shared lib;
  mypyc only regenerates the changed module's C on rebuild.

- sqlglot/__init__.py: tighten the `*__mypyc.so` bootstrap preloader.
  Under separate=True, per-module shared libs (e.g. errors__mypyc.so)
  live next to their .py sources and are resolved via normal dotted
  imports through the shim. Skip preloading those; keep the legacy
  preload behavior only for monolithic-hash .so files that lack a .py
  sibling.

- sqlglot/optimizer/__init__.py: make the top-level re-exports lazy via
  PEP 562 __getattr__. Under separate=True's eager cross-group init, the
  previous eager `from sqlglot.optimizer.optimizer import ...` could
  trigger while sqlglot's own __init__.py was mid-flight, hitting a
  circular-import ImportError on `from sqlglot import Schema, exp`.
  Lazy imports defer the cycle to first use.
@VaggelisD VaggelisD force-pushed the mypyc-separate-flag branch from 8db1da4 to e8129f7 Compare April 24, 2026 13:47

from __future__ import annotations

import typing as _t
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be _t, it's t right

import typing as _t

if _t.TYPE_CHECKING:
from sqlglot.optimizer.optimizer import RULES as RULES, optimize as optimize
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this section even necessary?

trigger this package's ``__init__.py`` before ``sqlglot`` has finished
binding names like ``exp`` / ``Schema``. Eager ``from sqlglot.optimizer.optimizer
import ...`` at module top used to kick off a circular-import cascade.
PEP 562 ``__getattr__`` lets the names resolve only when they're first
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you dig into this a little bit more, is it actually true? is the fix actually in mypyc?

Comment thread sqlglot/__init__.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants