Skip to content

WIP: Adding type hints to formatter.py #947

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

Closed
wants to merge 4 commits into from

Conversation

Ben-Reg
Copy link
Contributor

@Ben-Reg Ben-Reg commented Jan 4, 2022

Adding type hints to formatter.py.

A note on line 128. token = token.parent causes some problems with mypy because token is type _TokenType while token.parent is Optional[_TokenType]

The easy solution that I used below was to type tokensource like so:
tokensource: Iterable[MutableMapping[Any, str]]

Another approach would be something like this:
t: Optional[_TokenType] = token
t = t.parent
If we do it that way, we can type tokensource more accurately:
tokensource: Iterable[MutableMapping[_TokenType, str]]

@Ben-Reg Ben-Reg mentioned this pull request Jan 4, 2022
@codecov-commenter
Copy link

codecov-commenter commented Jan 5, 2022

Codecov Report

Merging #947 (0ca23b1) into main (4d33cc6) will decrease coverage by 0.00%.
The diff coverage is 85.71%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #947      +/-   ##
==========================================
- Coverage   68.75%   68.75%   -0.01%     
==========================================
  Files          63       63              
  Lines        9437     9440       +3     
==========================================
+ Hits         6488     6490       +2     
- Misses       2949     2950       +1     
Impacted Files Coverage Δ
bpython/formatter.py 92.00% <85.71%> (-3.46%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4d33cc6...0ca23b1. Read the comment docs.

@Ben-Reg
Copy link
Contributor Author

Ben-Reg commented Jan 6, 2022

New to this - should I reformat formatter.py with black and resubmit the code?

@thomasballinger
Copy link
Member

thomasballinger commented Jan 6, 2022

Looks like you got it, thank you! Sorry for the delay here.

A note on line 128. token = token.parent causes some problems with mypy because token is type _TokenType while token.parent is Optional[_TokenType]

I like the second one better, that seems truer to the code as it's currently written. Feel free to change the code though if it's easier to type, e.g. using a new temp variable or adding a new "if t is None" bailout.

@Ben-Reg
Copy link
Contributor Author

Ben-Reg commented Jan 6, 2022

Thanks, @thomasballinger. I think the only way to avoid using Any as a type is to use a temporary variable - the reason being that token has to be _TokenType (because of the line token = token.parent ... None cannot equal None.parent) and token.parent has to be Optional[_TokenType] because that method can return either a token or None.

At least, that's how it seems to me. I'll try another commit with a temp variable and you can make the call. I'm probably using too much of your time on the little details, but I appreciate the help!

@Ben-Reg
Copy link
Contributor Author

Ben-Reg commented Jan 14, 2022

@thomasballinger, is there anything else I need to do with this PR at this point?

@thomasballinger
Copy link
Member

thomasballinger commented Jan 14, 2022

Sorry about the delay, pinging with that comment was the perfect action. I'll look into this more this morning, right now when I run mypy locally I'm getting

(bpython) tomb ((0ca23b1...)) bpython$ mypy
bpython/formatter.py:114: error: No overload variant of "__init__" of "Formatter" matches argument type "Dict[str, str]"
bpython/formatter.py:114: note: Possible overload variants:
bpython/formatter.py:114: note:     def __init__(self, *, encoding: None = ..., outencoding: None = ..., **options: Any) -> None
bpython/formatter.py:114: note:     def __init__(self, *, encoding: str, outencoding: None = ..., **options: Any) -> None
bpython/formatter.py:114: note:     def __init__(self, *, encoding: None = ..., outencoding: str, **options: Any) -> None

which I'm sure it just my problem since it works in CI. Once I get this sorted (no action needed from you) I'll merge this.

@thomasballinger
Copy link
Member

I have to change the typing of **options to Any (which means Dict[str, Any] when used with **), which matches Pygments typing, to make this work locally for me. But it works without this change in CI. I figured this meant that my local enviroment was different than CI and CI should win, but I get the same thing from a fresh checkout on a linux box.

diff --git a/bpython/formatter.py b/bpython/formatter.py
index 20573bd..f216f21 100644
--- a/bpython/formatter.py
+++ b/bpython/formatter.py
@@ -28,7 +28,7 @@
 # mypy: disallow_untyped_calls=True


-from typing import MutableMapping, Iterable, TextIO
+from typing import Any, MutableMapping, Iterable, TextIO
 from pygments.formatter import Formatter
 from pygments.token import (
     _TokenType,
@@ -102,7 +102,7 @@ class BPythonFormatter(Formatter):
     straightforward."""

     def __init__(
-        self, color_scheme: MutableMapping[str, str], **options: str
+        self, color_scheme: MutableMapping[str, str], **options: Any
     ) -> None:
         self.f_strings = {}
         for k, v in theme_map.items():

I could imagine a reason for this: according to the types, it's not safe to include both encoding and outencoding with string values. Since I can do this with a fresh checkout, I think there's something wrong with our CI that we should fix, but in the meantime we can just make this change. I'll add this commit and merge.

@thomasballinger
Copy link
Member

Merged, thank you @Ben-Reg!

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.

4 participants