-
-
Notifications
You must be signed in to change notification settings - Fork 394
mypy: Fix erroring files. #135
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
Conversation
Hello @alenavolk, it seems like you have referenced an issue in your pull request, but you have not referenced that issue in your commit message(s). When you reference an issue in a commit message, it automatically closes the corresponding issue when the commit is merged. Please run An example of a correctly-formatted commit:
Thank you for your contributions to Zulip! |
I've just realized that the changes I've made in |
@alenavolk it looks like Travis is failing on Python 3.7 and 3.4 because we need to add the BTW you should come to our integrations/bots meeting tomorrow at 9AM http://zulip.readthedocs.io/en/latest/chat-zulip-org.html#chat-meetings |
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 looks good @alenavolk ! Left some comments. I find it surprising how many lines we have to exclude, all seeminglz because of mypy behaving incorrectly :-/
@@ -115,7 +115,7 @@ if __name__ == "__main__": | |||
zulip_client = zulip.init_from_options(args) | |||
try: | |||
log_files = json.loads(open(args.control_path, "r").read()) | |||
except (json.JSONDecodeError, IOError): | |||
except (json.JSONDecodeError, IOError): # type: ignore # error: Cannot determine type of 'IOError' |
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.
Hmm, I wonder why this happens.
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.
Have you tried marking this as a Union[]
of the two types? I've not needed to annotate exception blocks before, I think. It seems strange it would not determine the Union
from the tuple, in any case.
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.
@neiljp In this line any annotation apart from type: ignore
results in a misplaced type annotation
error.
@@ -50,6 +51,7 @@ | |||
# * stream "depot_subdirectory-commits" | |||
# * subject "change_root" | |||
def commit_notice_destination(path, changelist): |
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.
changelist
doesn't seem to be used at all in this functio (but it is passed as an argument in zulip_change-commit.py. @timabbott do you know anything more about this?
zulip/tests/__init__.py
Outdated
@@ -1,2 +1,2 @@ | |||
import pkgutil | |||
__path__ = pkgutil.extend_path(__path__, __name__) | |||
__path__ = pkgutil.extend_path(__path__, __name__) # type: ignore # error: Cannot determine type of '__path__' |
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.
Can you do # type: Iterable[Text]
? And from typing import Iterable, Text
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.
In typeshed, this is defined as:
def extend_path(path: Iterable[str], name: str) -> Iterable[str]: ...
so I would agree with @derAnfaenger, at this point.
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.
Fixed in both cases, thanks!
with self.assertRaises(SystemExit) as cm, patch('sys.stderr', new=six.StringIO()) as mock_stderr: | ||
cm = self.assertRaises(SystemExit) # type: ignore # error: No variant of "assertRaises" matches argument types | ||
mock_stderr = patch('sys.stderr', new=six.StringIO()) | ||
with cm as cm, mock_stderr as mock_stderr: |
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.
Would with cm, mockstderr:
suffice here? We already have bound them to variable names before.
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.
Alternatively, if typing is fixed, can the original line just be tidied to something like:
with self.assertRaises(SystemExit) as cm, patch('sys.stderr', new=six.StringIO()) as mock_stderr:
?
For the typing, that assertion appears to be present in the main zulip repo, and presumably type checks ok there, so that might be something to work from or provide a test case for mypy if it comes to that?
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.
@derAnfaenger Not really, it would make the test fail:
ERROR: test_invalid_arguments (tests.test_default_arguments.TestDefaultArguments)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/root/python-zulip-api/zulip/tests/test_default_arguments.py", line 27, in test_invalid_arguments
self.assertTrue(mock_stderr.getvalue().startswith("""usage: lorem ipsum
AttributeError: '_patch' object has no attribute 'getvalue'
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.
@neiljp Could you explain again how this line could be improved if typing
is fixed? It looks exactly the same now :)
@@ -68,7 +72,7 @@ def get_docs(): | |||
return doc_paths | |||
|
|||
def get_assets(): | |||
# type: () -> List[str] | |||
# type: () -> Iterator[str] |
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.
Since map()
returns a list, can we do from typing import List
and keep the List types? Also for the other occurrences in this file.
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.
That's how it was originally. I changed it to avoid this error: Incompatible return value type (got Iterator[str], expected List[str])
.
@neiljp FYI :)
@@ -72,7 +74,7 @@ def main(): | |||
# type: () -> None | |||
current_dir = os.path.dirname(os.path.abspath(__file__)) | |||
bots_dir = os.path.join(current_dir, "bots") | |||
bots_subdirs = map(os.path.abspath, glob.glob(bots_dir + '/*')) | |||
bots_subdirs = map(lambda d: os.path.abspath(d), glob.glob(bots_dir + '/*')) |
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.
map
takes a function as the first argument, so the initial version should be fine here.
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.
It definitely should, but it results in a bunch of weird errors:
Argument 1 to "map" has incompatible type Callable[[AnyStr], AnyStr]; expected Callable[[str], AnyStr]
Argument 1 to "isdir" has incompatible type "AnyStr"; expected "Union[bytes, str, _PathLike[Any]]"
Argument 1 to "parse_args" has incompatible type Iterator[AnyStr]; expected Iterator[str]
@neiljp FYI :)
zulip_bots/zulip_bots/provision.py
Outdated
@@ -35,6 +36,7 @@ def provision_bot(path_to_bot, force): | |||
|
|||
|
|||
def parse_args(available_bots): | |||
# type: (Iterator[AnyStr]) -> argparse.Namespace |
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's the reason for using AnyStr instead of str here?
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 was just trying to get rid of the errors below. You're right, str
works fine here. Fixed.
zulip_botserver/tests/__init__.py
Outdated
@@ -1,2 +1,2 @@ | |||
import pkgutil | |||
__path__ = pkgutil.extend_path(__path__, __name__) | |||
__path__ = pkgutil.extend_path(__path__, __name__) # type: ignore # error: Cannot determine type of '__path__' |
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.
Same as for zulip_bots
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.
Thanks for this :) I always enjoy seeing more type annotations! There are small things to be changed, some in the PR and some outside in typeshed (and maybe mypy). I look forward to seeing this progress :)
@@ -1,6 +1,7 @@ | |||
import irc.bot | |||
import irc.strings | |||
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr, Event, ServerConnection | |||
from typing import Any, Dict |
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 line makes the file pass mypy, I assume, but is it possible to use a specific type instead of Any
in __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.
That's a good point, but I don't think it's possible in this case.
@@ -115,7 +115,7 @@ if __name__ == "__main__": | |||
zulip_client = zulip.init_from_options(args) | |||
try: | |||
log_files = json.loads(open(args.control_path, "r").read()) | |||
except (json.JSONDecodeError, IOError): | |||
except (json.JSONDecodeError, IOError): # type: ignore # error: Cannot determine type of 'IOError' |
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.
Have you tried marking this as a Union[]
of the two types? I've not needed to annotate exception blocks before, I think. It seems strange it would not determine the Union
from the tuple, in any case.
@@ -10,7 +10,7 @@ ccache_data_encoded = sys.argv[3] | |||
|
|||
# Update the Kerberos ticket cache file | |||
program_name = "zmirror-%s" % (short_user,) | |||
with open("/home/zulip/ccache/%s" % (program_name,), "w") as f: | |||
with open("/home/zulip/ccache/%s" % (program_name,), "wb") as f: |
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.
Did mypy flag this due to the write
on the following line?
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.
Yep, the error is Argument 1 to "write" of "IO" has incompatible type "bytes"; expected "str"
.
zulip/tests/__init__.py
Outdated
@@ -1,2 +1,2 @@ | |||
import pkgutil | |||
__path__ = pkgutil.extend_path(__path__, __name__) | |||
__path__ = pkgutil.extend_path(__path__, __name__) # type: ignore # error: Cannot determine type of '__path__' |
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.
In typeshed, this is defined as:
def extend_path(path: Iterable[str], name: str) -> Iterable[str]: ...
so I would agree with @derAnfaenger, at this point.
with self.assertRaises(SystemExit) as cm, patch('sys.stderr', new=six.StringIO()) as mock_stderr: | ||
cm = self.assertRaises(SystemExit) # type: ignore # error: No variant of "assertRaises" matches argument types | ||
mock_stderr = patch('sys.stderr', new=six.StringIO()) | ||
with cm as cm, mock_stderr as mock_stderr: |
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.
Alternatively, if typing is fixed, can the original line just be tidied to something like:
with self.assertRaises(SystemExit) as cm, patch('sys.stderr', new=six.StringIO()) as mock_stderr:
?
For the typing, that assertion appears to be present in the main zulip repo, and presumably type checks ok there, so that might be something to work from or provide a test case for mypy if it comes to that?
try: | ||
module = import_module(module_name) | ||
module = import_module(module_name) # type: Any |
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.
types.ModuleType
?
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.
It looks very logical here, but for some reason it gives me the Module has no attribute "__version__"
error two lines below.
@@ -35,7 +35,7 @@ def get_bot_message_handler(self): | |||
# handler class. Eventually, we want bot's handler classes to | |||
# inherit from a common prototype specifying the handle_message | |||
# function. | |||
lib_module = import_module('zulip_bots.bots.{bot}.{bot}'.format(bot=self.bot_name)) | |||
lib_module = import_module('zulip_bots.bots.{bot}.{bot}'.format(bot=self.bot_name)) # type: Any |
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.
types.ModuleType
again here?
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 one gives me the Module has no attribute "handler_class"
error.
zulip_bots/zulip_bots/test_lib.py
Outdated
@@ -61,7 +61,7 @@ def check_expected_responses(self, expectations, expected_method='send_reply', | |||
# To test send_message, Any would be a Dict type, | |||
# to test send_reply, Any would be a str type. | |||
if isinstance(expectations, dict): | |||
expected = [(k, v) for k, v in expectations.items()] | |||
expected = [(k, v) for k, v in expectations.items()] # type: Sequence[Tuple[str, Any]] |
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 a list comprehension, in the implementation, so just type it as that?
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 line was deleted in master
.
@@ -75,7 +77,7 @@ def main(): | |||
sys.exit(1) | |||
|
|||
with patch('zulip.Client') as mock_client: | |||
mock_bot_handler = ExternalBotHandler(mock_client, bot_dir) | |||
mock_bot_handler = ExternalBotHandler(mock_client, bot_dir) # type: Any |
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.
Is this necessary since this object gets 'monkey patched' later?
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 so, otherwise I get several Cannot assign to a method
errors right below (and many others later).
try: | ||
module = import_module(module_name) | ||
module = import_module(module_name) # type: Any |
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.
types.ModuleType
?
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.
Same error as in zulip_bots/setup.py
: Module has no attribute "__version__"
.
Regarding the failing Travis build. It looks like adding
causes the Travis uses this script to recreate the environment every time it runs the tests, that's why the build fails even though all tests have passed locally. I've tried adding the
are installed from the same place, and The only solution I can think of at the moment is to change the problematic imports as follows:
It fixes the problem locally, and I think it'll make the Travis build pass as well. |
@alenavolk I think that means we need to add |
@timabbott I've added
The same thing in Unfortunately, it looks like I'll still have to use the |
|
||
from zulip_bots.lib import run_message_handler_for_bot | ||
from zulip_bots.provision import provision_bot | ||
|
||
current_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
def import_module_from_source(path, name=None): | ||
# type: (Text, Optional[Text]) -> Any |
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.
@neiljp I think this is the only place where I can use types.ModuleType
right now.
@neiljp Thank you so much for reviewing this! I really appreciate it. Today I tried annotating the module instances with
Does it mean I should keep the Also, I know I could use
but I'm not sure if it makes sense. Wouldn't it be better to keep Looking forward to your reply! |
@alenavolk if you have a subset of these commits that are fully reviewed and pass tests, it could be good to open those in a new PR so that we can start shrinking this. Though .. I guess we need to figure out the Travis issue with |
Actually, looking at the error, I think it's just that |
@timabbott Unfortunately, the error Travis is showing right now is not the only one, there are actually three files failing the Travis build. It's not a complicated problem or anything, but since we don't have a common understanding of how to fix it, I think the best approach would be to first shrink this PR as much as possible and then continue this discussion. I shouldn't have made a PR this big in the first place, but oh well... I'll work with what I've got now :) |
@alenavolk which 3 files are failing? I think we might want to just do the |
@timabbott The problem in a nutshell is that
or use the We could also just leave these files on the |
372bee6
to
4b40ce9
Compare
Hello @alenavolk, it seems like you have referenced an issue in your pull request, but you have not referenced that issue in your commit message(s). When you reference an issue in a commit message, it automatically closes the corresponding issue when the commit is merged. Please run An example of a correctly-formatted commit:
Thank you for your contributions to Zulip! |
4b40ce9
to
25d6c68
Compare
Hello @alenavolk, it seems like you have referenced an issue in your pull request, but you have not referenced that issue in your commit message(s). When you reference an issue in a commit message, it automatically closes the corresponding issue when the commit is merged. Please run An example of a correctly-formatted commit:
Thank you for your contributions to Zulip! |
Merged, thanks @alenavolk! This cleaned up a lot of issues. I think we can probably deal with any remaining |
Finally, I have a PR ready :) Things to keep in mind while reviewing:
I annotated strings as
Text
in files that didn't have any annotations, and asstr
in files that already hadstr
annotations.I made a couple of minor changes to the code in places where I thought it made sense. I tested these changes, but it would be great to have someone look over.
I tried to minimize using
type: ignore
, but you'll still see it in a couple of places. Please let me know if you can suggest a way to avoid that.Fixes #127.