-
-
Notifications
You must be signed in to change notification settings - Fork 410
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merge .pyi files #926
Merge .pyi files #926
Conversation
ast_utils, grammar, and indenter
load_grammar, reconstruct, and visitors
My idea: I feel like we can do something involving strings and |
I'd rather not add dependencies, even if really basic ones. It might affect the standalone parser. I think we can keep those exceptions in .pyi files for now, until we find a better solution. |
As for adding type annotations to internal code, it might make sense in situations where the type isn't obvious. But I prefer if we went through that on a separate PR. |
Sounds good. I'll only apply the existing types from the .pyi's in this PR. |
exceptions, lark, and tree
An idea I had for
However, the same probably won't work for |
What if we only support type checking for 3.8 and up? The code will still run with 3.6 |
Type checking need not be limited to 3.8+. Upon further inspection, I don't think |
__init__, lexer, and parsers/__init__
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments. Not all of them are really directly solvable problems, but some are more a TODOs for a potentially future PR. I wouldn't be opposed if you decided to 'fix' none of these.
|
||
if TYPE_CHECKING: | ||
from .lark import PostLex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can just move the definition of PostLex
into common.py
. It fits better here anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not lexer.py
?
Btw this is an opportunity to change the postlex interface completely, if we wish to.
@@ -23,41 +19,51 @@ | |||
except ImportError: | |||
regex = None | |||
|
|||
|
|||
###{standalone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@erezsh This can happen in another PR, but we might want to consider removing type annotations like we are removing docstrings from the standalone parser.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that we should, if we can.
keep_all_tokens: bool | ||
tree_class: Any | ||
parser: 'Literal["earley", "lalr", "cyk", "auto"]' | ||
lexer: 'Union[Literal["auto", "standard", "contextual", "dynamic", "dynamic_complete"], Type[Lexer]]' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can instead define types inside a version guarded if-statement that when Literal
is not available is just Union[str, Type[Lexer]]
(and similar for all other types here). Not sure if it is better thou.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the current way. It provides the precision of Literal
even when type checking on 3.6 and 3.7.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the current implementation do when typing_extensions
is not installed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation executes normally because the import of typing_extensions
is wrapped in an if TYPE_CHECKING
. I believe it is reasonable to assume that typing_extensions
will be installed when TYPE_CHECKING
is true because typing_extensions
is a dependency of mypy
.
@@ -9,12 +10,23 @@ | |||
###{standalone | |||
from copy import copy | |||
|
|||
from types import ModuleType | |||
from typing import ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to have duplicates imports inside of ###{standalone
raw = None | ||
type = None | ||
if TYPE_CHECKING: | ||
from .common import LexerConf |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably a TODO for later, but I think we can instead of guarding the circle with TYPE_CHECKING
move more stuff into common.py
. That is why it exists. ( In this case, the definition of TerminalDef
/the Patterns/Token
)
lark/lexer.py
Outdated
"""Lexer interface | ||
|
||
Method Signatures: | ||
lex(self, text) -> Iterator[Token] | ||
""" | ||
lex = NotImplemented | ||
lex: Callable[..., Iterator[Token]] = NotImplemented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are inheriting from ABC
, this should just be a normal abstractmethod
.
lark/lexer.py
Outdated
@@ -452,7 +494,7 @@ def __init__(self, conf, states, always_accept=()): | |||
def make_lexer_state(self, text): | |||
return self.root_lexer.make_lexer_state(text) | |||
|
|||
def lex(self, lexer_state, parser_state): | |||
def lex(self, lexer_state: Any, parser_state: Any) -> Iterator[Token]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another TODO for potentially later: corrects these annotations
@@ -1072,7 +1082,7 @@ def _unpack_definition(self, tree, mangle): | |||
return name, exp, params, opts | |||
|
|||
|
|||
def load_grammar(self, grammar_text: str, grammar_name: str="<?>", mangle: Callable[[str], str]=None) -> None: | |||
def load_grammar(self, grammar_text: str, grammar_name: str="<?>", mangle: Optional[Callable[[str], str]]=None) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I am wrong here, but isn't Optional
automatically added when =None
is the default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I didn't know about that feature. However, it looks like its use is no longer recommended. https://stackoverflow.com/questions/62732402/can-i-omit-optional-if-i-set-default-to-none
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha. I didn't see that it was deprecated. Good to know.
lark/common.py
Outdated
postlex: 'PostLex' = None | ||
callbacks: Optional[Dict[str, _Callback]] = None | ||
postlex: 'Optional[PostLex]' = None | ||
callbacks: Dict[str, _Callback] = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to provide values when annotation on classes?
lark/lexer.py
Outdated
raw: str = None | ||
type: str = None | ||
raw: Optional[str] = None | ||
type: Optional[str] = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not optional. It is also more of a ClassVar
@chanicpanic Thanks a lot! I'm sure it was hard work. Sorry it took me so long to review. One question, is |
@erezsh No problem. I'm glad I can help. Annotating the return type of |
I see, thanks for explaining. It's a little surprising, if I already run mypy, why wouldn't I want to scan all the functions by default? |
I believe mypy behaves this way to make it easier for existing projects to adopt type annotations little by little. Annotations can be applied to the most important or straightforward functions first without receiving a bunch of nasty errors for those that have not been annotated. Also, some functions/variables may be so dynamic that it is hardly worth the trouble to try to declare precise types for them. Thus, you can opt to omit annotations and mypy won't complain. |
The package was removed in PR lark-parser#926. When trying to install lark upstream, pip fails: > error: package directory 'lark-stubs' does not exist
I started merging the stub files into the code. Here are a couple things I noticed so far:
lexer.py
the signatures of some methods ofTraditionalLexer
andContextualLexer
do not match the signatures inlexer.pyi
.lark.pyi
andtree.pyi
usetyping.Literal
andtyping.Protocol
which are new in Python 3.8. The mypy docs suggest using thetyping_extensions
package, but it may not be installed. How do we want to approach this?One other question: Would you like me to add type annotations to more functions where possible, or do you only want them on public interfaces?