Skip to content

Lazy-load syntax validators on attr access#8

Open
djrobstep wants to merge 2 commits into
willynilly:mainfrom
djrobstep:lazy-load-syntax-validators
Open

Lazy-load syntax validators on attr access#8
djrobstep wants to merge 2 commits into
willynilly:mainfrom
djrobstep:lazy-load-syntax-validators

Conversation

@djrobstep

Copy link
Copy Markdown

Currently this module has quite a large import time (over 0.5 sec on my machine).

This PR reduces this by lazy-loading the syntax validators lazily on attribute access.

@jkowalleck

Copy link
Copy Markdown
Collaborator

the syntax_parser = Lark(grammar, start=["iri", "iri_reference", "absolute_iri"], parser=RFC3987_SYNTAX_PARSER_TYPE) is still not lazy

@djrobstep

Copy link
Copy Markdown
Author

I suppose I can move that too

@djrobstep

Copy link
Copy Markdown
Author

Moved. It is probably possible to go further and entirely avoid loading lark upfront. But this feels like a big enough change already for one PR.

@gogasca

gogasca commented Jan 6, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to reduce rfc3987_syntax import time by deferring creation of Lark parsers/validators until they’re first accessed via module attribute access.

Changes:

  • Removed eager creation of the shared syntax_parser and term-specific is_valid_syntax_<term> helpers at import time.
  • Added module-level __getattr__ to lazily create and cache the shared parser and term-specific validator functions.
  • Updated parse() to retrieve the lazily created syntax_parser via module attribute access.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +100 to +104
def __getattr__(name):
"""
Lazily create attributes, in particular syntax validators, when accessed.

is_valid_syntax_ucschar = make_syntax_validator("ucschar")
When an attribute like 'is_valid_syntax_iri' is accessed, this function

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

There are existing pytest tests for is_valid_syntax, but this PR adds a new public access pattern (lazy module attributes via __getattr__). Add coverage that imports and calls at least one term-specific helper (e.g. from rfc3987_syntax import is_valid_syntax_iri) and that accessing syntax_parser/a validator succeeds and returns a callable, so regressions in the lazy-loading mechanism are caught.

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +94
if term_name not in RFC3987_SYNTAX_TERMS:
return None

is_valid_syntax_ipchar = make_syntax_validator("ipchar")
return make_syntax_validator(term_name)

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

get_syntax_validator only creates helpers when term_name is in RFC3987_SYNTAX_TERMS, but several grammar terms that previously had is_valid_syntax_<term> helpers (e.g. ipath_absolute, ipath_rootless, ipath_noscheme, ipath_empty, ipath) are not in that list. As a result, accessing those helpers will now raise AttributeError (breaking the documented API). Consider either expanding RFC3987_SYNTAX_TERMS to include all supported grammar rules that should have helpers, or removing this membership gate and letting make_syntax_validator/Lark determine validity (possibly with a clearer error for unknown terms).

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +117
_attr_cache[name] = syntax_parser
return syntax_parser
if validator := get_syntax_validator(name):
_attr_cache[name] = validator

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

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

__getattr__ caches values only in _attr_cache but does not write them into the module namespace. This means every subsequent access to syntax_parser (and validators) will still go through __getattr__, adding avoidable overhead to hot paths like parse(). Consider also assigning the created object into globals()[name] (or setattr(sys.modules[__name__], name, value)) so future lookups bypass __getattr__.

Suggested change
_attr_cache[name] = syntax_parser
return syntax_parser
if validator := get_syntax_validator(name):
_attr_cache[name] = validator
_attr_cache[name] = syntax_parser
globals()[name] = syntax_parser
return syntax_parser
if validator := get_syntax_validator(name):
_attr_cache[name] = validator
globals()[name] = validator

Copilot uses AI. Check for mistakes.
@jkowalleck

Copy link
Copy Markdown
Collaborator

Hi! Since this repository is no longer actively maintained, I created and now maintain a fork of this package long-term:

Would you mind retargeting (or reopening) this pull request against the maintained fork so your fix/feature can be reviewed and merged there?

Thank you!

@jkowalleck

Copy link
Copy Markdown
Collaborator

continued in jkowalleck#43

@jkowalleck

Copy link
Copy Markdown
Collaborator

Hi! Since this repository is no longer actively maintained, I created and now maintain a fork of this package long-term:

* PyPI: https://pypi.org/project/rfc3987-syntax2/

* Repository: https://github.com/jkowalleck/rfc3987-syntax2

Would you mind retargeting (or reopening) this pull request against the maintained fork so your fix/feature can be reviewed and merged there?

Thank you!

was solved via https://github.com/jkowalleck/rfc3987-syntax2/releases/tag/v1.3.0

@jkowalleck jkowalleck linked an issue Jul 23, 2026 that may be closed by this pull request
@jkowalleck

Copy link
Copy Markdown
Collaborator

this has been solved in maintained fork of the library since version 1.3.0

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.

Import time improvements

4 participants