Skip to content

perf(assert_name): skip per-char generator -- 25% faster schema build - #305

Open
dexhunter wants to merge 1 commit into
graphql-python:mainfrom
dexhunter:perf/assert-name-isidentifier
Open

dexhunter wants to merge 1 commit into
graphql-python:mainfrom
dexhunter:perf/assert-name-isidentifier

Conversation

@dexhunter

Copy link
Copy Markdown
Contributor

TL;DR

  • Make assert_name() faster, which runs for every name during schema construction.
  • Valid names now return after two C-level string checks instead of one Python call per character.
  • build_ast_schema benchmark on the GitHub SDL, median of best times: 14.40 ms -> 10.79 ms, 25.0% faster.
  • PYTHONPATH=src python -m pytest tests -q: 3625 passed, 18 skipped.

Refs #304

What & Why

Before, assert_name() checked the name tail with a generator.
It called is_name_continue() once for each character, so long names cost many Python calls.

Now it first checks isinstance(name, str) and name.isascii() and name.isidentifier().
For ASCII text, a Python identifier is exactly a GraphQL name: [_a-zA-Z][_a-zA-Z0-9]*.
Valid names return at once.

Invalid names keep the same checks in the same order, so each error type and message stays the same.
The tail check now uses name[1:].replace("_", "") with isascii() and isalnum().
If the tail is valid but the name is not, only the first character can be wrong.
The code then raises the "must start with" error.

Results

Situation Before After Change
build_ast_schema on the GitHub SDL (assume_valid=True) 14.40 ms 10.79 ms 25.0% less time
build_client_schema on the GitHub introspection result 13.97 ms 10.43 ms 25.3% less time
assert_name on 10,000 valid names 6.94 ms 0.69 ms 90.0% less time
assert_name on 10,000 invalid names 13.32 ms 8.62 ms 35.3% less time
parse on the large query (does not call assert_name) 38.43 ms 37.90 ms No change (within noise)

Each value is the best of 15 runs, then the median of 7 alternating processes per version.
CPython 3.12.13, Linux x86-64, AMD EPYC 9R14, one dedicated CPU core.

Why this is safe and easy to maintain

The change touches one function and adds no new helpers or dependencies.
Valid names give the same return value, and invalid names give the same exception class and message.
tests/type/test_assert_name.py, the schema build tests and the doctests in the module cover these cases.

Validation

  • PYTHONPATH=src python -m pytest tests -q: 3625 passed, 18 skipped.
  • PYTHONPATH=src python -m pytest --doctest-modules src/graphql/type/assert_name.py: 2 passed.
  • Benchmark: pytest tests/benchmarks/test_build_ast_schema.py tests/benchmarks/test_build_client_schema.py --benchmark-only.

AI assistance

Candidate changes were generated with Codex (gpt-6.1-sol) and tracked with Weco Observe.
An automated agent selected the final change and ran the tests and benchmarks above.

Weco share link: https://dashboard.weco.ai/share/nBw9xQ9xWsK2u9f9hqyIJaqqBFFOsN7L

assert_name() checked the name tail with a generator that called
is_name_continue() once per character. For ASCII text, str.isidentifier()
is true exactly for [_a-zA-Z][_a-zA-Z0-9]*, so valid names now return
after isascii() and isidentifier(). Invalid names keep the same checks
in the same order, so error classes and messages are unchanged.

build_ast_schema on the GitHub SDL: 14.40 ms -> 10.79 ms (25% less time).

Co-Authored-By: Aiden <[email protected]>
@dexhunter
dexhunter requested a review from Cito as a code owner November 7, 2026 02:24
@codspeed

codspeed Bot commented Nov 7, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 47.02%

1 warning

⚠️ 2 benchmarks with a significant change ran on different hardware

Their base and head results were measured on machines with a different CPU, core count or memory, so the changes might not come from the code. Run base and head on the same runner type.

Learn more about Macro Runners

See affected benchmarks

⚡ 2 improved benchmarks
✅ 18 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
⚡ test_build_schema_from_ast 225.3 ms 151.7 ms +48.59%
⚡ test_build_schema_from_introspection 238.4 ms 163.9 ms +45.47%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing dexhunter:perf/assert-name-isidentifier (3cd8b92) with main (1d505c1)

Open in CodSpeed

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.

1 participant