19 New graduates. From this year, I have been touching the server side and doing various things.
This time, I will talk about making it easy to understand the increase and decrease of error output of mypy in conjunction with git.
It is a tool that performs static analysis on type annotations in python. I recommend you to read the article of the ancestor. mypy will do it I did mypy
The beginning of the matter was that the version of mypy in the deal was not updated for a long time (0.540). If you look at the Release Notes, it says Friday, 20 October 2017, etc.
When I tried to install the latest version locally with a light feeling, I got a lot of errors related to the check items added in the update. If you add the option to suppress it for the time being, it will pass, but ... this is ...
And I tried to fix the error at hand, but it became painful normally. Since errors are unevenly distributed throughout the project code, which is quite large, it is mentally painful that no improvement can be seen by just fixing it a little ...
It's impossible. Let's visualize ...
Visualization is an overstatement (because it is information that can be seen from the beginning), Wouldn't it be nice if the list of errors I crushed was displayed in an easy-to-understand manner? I thought. The policy is simple: run mypy twice before and after the change to get the diff. There is a policy that it should be possible to do something by calling the difference between the work tree and HEAD in conjunction with git. The execution time will be doubled, but on the other hand, mypy can be targeted only to the difference file, so I will go with wishful thinking that it is okay.
That's why I made it. https://github.com/fujita-ma/mymypy
There's no serious reason to write in rust, Since there was a lot of line-by-line text processing, I think it was easy to write iterator processing without stress. It's okay to use python, but to be honest, I wanted to do it in a language I didn't use at work.
Try it with the code in the mypy sample. http://www.mypy-lang.org/examples.html
main.py
class BankAccount:
def __init__(self, initial_balance=0):
self.balance = initial_balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
def overdrawn(self):
return self.balance < 0
my_account = BankAccount(15)
my_account.withdraw(5)
print(my_account.balance)
Let's run mypy.
❯ mypy --strict ./
main.py:2: error: Function is missing a type annotation
main.py:4: error: Function is missing a type annotation
main.py:6: error: Function is missing a type annotation
main.py:8: error: Function is missing a return type annotation
main.py:11: error: Call to untyped function "BankAccount" in typed context
I'm getting an error. After committing this once, modify some annotations and try running mypy and mymypy respectively.
main.py
class BankAccount:
def __init__(self, initial_balance: int = 0) -> None: # Annotated
self.balance = initial_balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
def overdrawn(self):
return self.balance < 0
my_account = BankAccount(15)
my_account.withdraw(5)
print(my_account.balance)
❯ mypy --strict ./
main.py:4: error: Function is missing a type annotation
main.py:6: error: Function is missing a type annotation
main.py:8: error: Function is missing a return type annotation
main.py:12: error: Call to untyped function "withdraw" in typed context
❯ mymypy
main.py
-main.py:2:_: error: Function is missing a type annotation
main.py:4:4: error: Function is missing a type annotation
main.py:6:6: error: Function is missing a type annotation
main.py:8:8: error: Function is missing a return type annotation
-main.py:11:11: error: Call to untyped function "BankAccount" in typed context
+main.py:12:12: error: Call to untyped function "withdraw" in typed context
The crushed error is highlighted in red! Also, as a by-product, the added error is highlighted in green. It's common to fix an error and get another hidden error. I'll crush everything properly.
If you add all annotations properly, it will look like ↓.
main.py
class BankAccount:
def __init__(self, initial_balance: int = 0) -> None:
self.balance = initial_balance
def deposit(self, amount: int) -> None:
self.balance += amount
def withdraw(self, amount: int) -> None:
self.balance -= amount
def overdrawn(self) -> bool:
return self.balance < 0
my_account = BankAccount(15)
my_account.withdraw(5)
print(my_account.balance)
❯ mypy --strict ./
❯ mymypy
main.py
-main.py:2:_: error: Function is missing a type annotation
-main.py:4:_: error: Function is missing a type annotation
-main.py:6:_: error: Function is missing a type annotation
-main.py:8:_: error: Function is missing a return type annotation
-main.py:11:11: error: Call to untyped function "BankAccount" in typed context
I was able to crush 5 errors by my own work. I'm happy.
Let's play a little.
I'm going to handle revisions according to git diff
, so if you specify an appropriate commit, you can get the difference between them.
Take a peek at mypy's repository to catch commits.
a5005f4aa977e4911bce5c828fd707ca8680d592
The `inner_types` attribute seems to have no effect.
I found a commit that seems to have been refactored.
Let's clone it and run it on mymypy.
❯ mymypy a5005f4~ a5005f4
mypy/checker.py
mypy/checker.py:64:64: error: Module 'mypy.semanal' has no attribute 'set_callable_name'
-mypy/checker.py:2813:_: error: Too many arguments for "PartialType"
-mypy/checker.py:2823:_: error: Too many arguments for "PartialType"
mypy/checker.py:2959:2959: error: unused 'type: ignore' comment
-mypy/checker.py:3022:_: error: "PartialType" has no attribute "inner_types"
-mypy/checker.py:3024:_: error: "PartialType" has no attribute "inner_types"
mypy/checker.py:4137:4133: error: unused 'type: ignore' comment
-mypy/checker.py:4311:_: error: "PartialType" has no attribute "inner_types"
mypy/checkexpr.py
mypy/checkexpr.py:203:203: error: unused 'type: ignore' comment
-mypy/checkexpr.py:592:_: error: "PartialType" has no attribute "inner_types"
-mypy/checkexpr.py:606:_: error: "PartialType" has no attribute "inner_types"
mypy/checkexpr.py:2368:2361: error: Returning Any from function declared to return "Optional[str]"
mypy/checkexpr.py:3003:2996: error: unused 'type: ignore' comment
mypy/type_visitor.py
mypy/type_visitor.py:167:167: error: unused 'type: ignore' comment
mypy/type_visitor.py:207:207: error: unused 'type: ignore' comment
mypy/type_visitor.py:229:229: error: unused 'type: ignore' comment
-mypy/type_visitor.py:293:_: error: "PartialType" has no attribute "inner_types"
mypy/types.py
mypy/types.py:190:190: error: unused 'type: ignore' comment
mypy/types.py:497:497: error: Returning Any from function declared to return "T"
mypy/types.py:520:520: error: Returning Any from function declared to return "T"
mypy/types.py:808:808: error: Returning Any from function declared to return "Union[Dict[str, Any], str]"
mypy/types.py:1557:1557: error: Returning Any from function declared to return "T"
mypy/types.py:1669:1669: error: Returning Any from function declared to return "T"
mypy/types.py:1789:1786: error: Returning Any from function declared to return "T"
mypy/types.py:1844:1841: error: unused 'type: ignore' comment
mypy/types.py:1889:1886: error: Returning Any from function declared to return "T"
You can see the effect of refactoring. Fun ✌ ('ω' ✌) Three ✌ ('ω') ✌ Three (✌'ω') ✌ (dead language)
I made it with an appropriate policy after a change of mood, but I am satisfied because it was able to be displayed with a good feeling. I will use it for my business because it is a big deal. ~~ If you actually use it, you will find many bugs ~~
Recommended Posts