[plugins/help] Triggering node visits?
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
Hello there 👋
First of all, I post here instead of on Gitter because I think my question is a bit long and it would pollute the thread while being hard to respond too. Also, Thanks for all the documentation in source code, it helps a lot already!
I'm trying to write a plugin for my paramclasses library and I would love some help! For a starting point, I'll focus on my protected function/decorator, which essentially provides runtime equivalent for both typing.finaland typing.Final during paramclasses' definition:
class Foo(ParamClass):
x = protected(0) # Unmodifiable in instances and subclasses
@protected
def bar(self) -> None:
"""Works on methods."""
@protected
@property
def baz(self) -> int:
"""Also works on properties."""
return 0
I started understanding a bit more how mypy plugins work, and I currently have the following:
METAPARAMCLASS_FULLNAME = "paramclasses.paramclasses._MetaParamClass" # Paramclasses have this as metaclass
class CustomPlugin(Plugin):
"""Help mypy undestand ``@protected`` and ``protected()``."""
def get_metaclass_hook(self, fullname) -> Callable[[ClassDefContext], None] | None:
"""Update paramclass definition."""
return paramclass_finder_hook
def get_base_class_hook(self, fullname) -> Callable[[ClassDefContext], None] | None:
"""Update paramclass definition."""
return paramclass_finder_hook
def paramclass_finder_hook(ctx: ClassDefContext):
"""Identify paramclasses and trigger class def modification."""
mcs = ctx.cls.info.metaclass_type
if mcs is not None and mcs.type.fullname == METAPARAMCLASS_FULLNAME:
modify_paramclass_def(ctx.cls)
def modify_paramclass_def(cls: ClassDef) -> None:
"""Handle ``@property`` and ``protected()``."""
replace_protected_decorator_with_final(cls)
replace_protected_assignment_with_Final(cls)
def replace_protected_decorator_with_final(cls: ClassDef) -> None:
"""Visit decorator nodes, move @protected, add to original_decorators, mark node as final."""
# Help pls!
As you can see, I think I'm pretty close to a first POC, I just need to know how to visit cls in replace_protected_decorator_with_final and modify targetted nodes. For that, I'll take inspiration from mypy.semanal.SemanticAnalyzer.visit_decorator() I think?
But I have so many questions:
- Is my overall approach sound/in the spirit of mypy plugins API?
- How can I trigger a visit? I thought about writing a custom semantic analyzer but I don't know how to "trigger" it?
- If I write one, should my
SemanticAnalyzerinherit from(NodeVisitor[None], SemanticAnalyzerInterface, SemanticAnalyzerPluginInterface)just like the one from mypy/semanal.py? I don't really understand what's useful and when. - Should I carry out both
replace_protected_decorator_with_finalandreplace_protected_assignment_with_Finalsimultaneously with a unique semantic analyzer?
Thanks a lot in advance!!!
Élie
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the plugin hook implementations in the issue and read mypy/semanal.py, especially SemanticAnalyzer.visit_decorator(). Determine whether the existing plugin API supports visiting and modifying the targeted class nodes, and whether a custom semantic analyzer is appropriate; done means establishing a supported approach or documenting that the requested traversal is unavailable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100