-
Notifications
You must be signed in to change notification settings - Fork 259
Fix for issue #524 #527
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
Fix for issue #524 #527
Conversation
Hello, and thanks for your contribution! I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA). Unfortunately our records indicate you have not signed the CLA. For legal reasons we need you to sign this before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue. Thanks again to your contribution and we look forward to looking at it! |
Just a heads up: I signed that (right now-prior to submitting the PR). If there's an issue with it, I am more than willing to sign it again. |
Hm, it seems you staged and committed all of the files you modified. Did you perhaps run Also we probably want a test for this. This is somewhat open ended. One idea is to use |
Hmm, thank you for your feedback (I totally did run |
|
||
Protocol.__doc__ = Protocol.__doc__.format(bases="Protocol, Generic[T]" if | ||
if Protocol.__doc__ is not None: | ||
Protocol.__doc__ = Protocol.__doc__.format(bases="Protocol, Generic[T]" if | ||
OLD_GENERICS else "Protocol[T]") |
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.
You should also add four spaces of indent 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.
Thank you! C: should I commit a second time (or just re-write the initial commit)?
I did an overhaul of the PR markdown. I realized that while I kind-of understood the issue, I couldn't even reproduce it consistently [didn't understand it other than syntactically], let alone test it. After trying many many different things (and spending a lot of time trying to test the wrong module), I finally was able to reproduce the error consistently AND provide a solid way of confirming the issue is resolved. As for the review: please let me know if you'd like me to make another commit to fix that or if you would rather I reset the head->applied the review-fix -> re-committed. Thank you very much for your patience! C: |
According to python/mypy#4161, I guess the policy is to not rewrite commits. |
You can just commit on your branch and push. As I can see from the current state of PR you did everything right. The only thing missing now is a test. See @ethans post above
|
Indeed. Initially, I misinterpreted that statement as "We need a way to make sure this works manually." While the former is important, I realize now that what he meant was we need a written test-case (and I think using
|
There should be a test for both typing.py and typing_extensions.py (one in each test_* file). The reasoning is that while the issue here was in typing_extensions.py, a) many things move from typing_extension.py into typing.py and b) we don't want regressions on this behavior in either file.
This seems fine to me.
pytest is used as the test runner, but automatically picks up unittest test cases.
Ideally you should research these topics independently, the internet is a great resource! However, you can also ask on the typing Gitter chat channel for issues more closely pertaining to project specific things. I should usually be around to answer questions, and if I am not, someone else usually is. |
So, I'm having a little bit of trouble isolating the issue with compile. Since compile itself needs some kind of string for a source, I only know of one option: read in the entire file (I tried using inspect, but since the source for that is tabbed, it just raises SyntaxErrors). But, doing so doesn't really specify that the issue is with the Protocol class (as when I exec() to test, the caught AttributeError could be anywhere within the file). While the below does produce the failed test when using the old file, and does not produce a failed test when using the newly committed changes (using optimize=2), I feel like this is a) hacky as heck, and b) very brittle. Interestingly, even with the old file, it is able to compile it with optimize=2, the issue displays itself when you exec() it. Questions:
Just a heads up, this looks terrible, sorry about that:
Edit: I'm going to commit, so we can review it, but I personally don't like this as a test at all (I'm only going to commit the typing_extensions test first. If we can find a better solution/agree on the commit, then I'll create another test for typing as well. Also, I'm bad, and forgot to run git diffs before I pushed (sorry about the multi-commit). Edit2: Ah, I see some errors have occurred with my test (it really didn't like that). Hmm...(rewriting test). Edit3: I think using inspect is much cleaner here. If not, I can always read it directly from |
Just checking that file compiles with optimizations seems OK to me. Also I would add the same tests on Python 2 (although it doesn't fail now, it would be useful to prevent this in future). There are two folders: |
I'm having some issues porting the tests over to py2 directly (the compile() for py2 doesn't support an optimize flag like it does in py3). I was also looking at the pytest option to see if I could pass an optimization flag for py2, and I couldn't find anything about it. I think I may be able to come up with a (really hackish) way to check the py2 sources using os.system/subprocess.call. I'm doing some testing with them right now, to see if I can get something to work (I am able to reproduce the error [tried to do something to a nonetype docstring due to OO] if something like the original issue happens in the other sources, and it does indeed break correctly when this is used: WIP-1: I'm pretty sure I got something to work. It is SO brittle though (I went with my initial idea and ended up using subprocess.check_output). Oh no, I broke it. :C WIP-2: YAY-Still broken. Now the tox tests don't work at all, but all the py.test and pytests do: OH, it's because I used os.getcwd() [which would be different using tox, because tox's originating cwd must be elsewhere than the top level directory]? No, I don't think so, if I remove the two typing tests, the typing_extensions ones work fine, which means there's an issue with what I'm doing inside test_typing for both py2/py3. Hmm...I'm going to sleep for now, I'll be on tomorrow working on this all day :D WIP-3: Hmm, the test_typing with both py2 and py3 have some serious problems when testing them with tox. I'm not exactly sure why this is. There seems to be something calling super() which is making a new thing, which is calling super() which is...so on and so forth. WIP-4: Oh man I'm bad. Something seems to be failing with unittest.discover(). Alright, that's real interesting. I guess re-loading the module like that is causing isinstance some serious problems. I think I may have an idea to get this to work, but it'll be very brittle (again). :C Oh, tox isn't run on typing_extensions. Hmm...Still. I think I have found a way to make it work (testing/duplicating errors tonight, will commit tomorrow). Tests:
|
I found the issue with my old tests and wrote new tests for it! :DThey're kind of (extremely) brittle, but they do test the issue successfully. I'll try to explain some of the decisions I made regarding the test. My reason for choosing to use subprocess over compile:
tox doesn't run any tests found in typing_extensions (but just incase, I tox'd them with the new tests anyway). I decided to use a very similar testing method that I tried to use for typing_extensions_py2 because it doesn't reload the module (very important). I have made a handy checklist for testing my tests (seriously, sorry) and will post it below. Tests of tests:
|
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.
Two more minor comments.
src/test_typing.py
Outdated
@@ -1,7 +1,10 @@ | |||
import contextlib | |||
import collections | |||
import inspect |
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.
inspect
is not used anymore.
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.
Removed inspect (latest commit).
python2/test_typing.py
Outdated
subprocess.check_output('python -OO {}'.format(file_path), | ||
stderr=subprocess.STDOUT, | ||
shell=True) | ||
except subprocess.CalledProcessError as e: |
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.
You are not using e
, below, so ... as e
is not needed.
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.
Hm, do you think the specific catch is still necessary? I ended up removing it on my latest commit as a whole and can put it back if you think it is. :D
I think we can keep the current version of the tests (unless @ethanhs has another ideas). I can merge this after you fix the remaining comments. |
This testing method is acceptable to me. |
I decided to remove the error for the specific catch across all excepts (all four tests). I also removed the inspect module from test_typing.py and double-checked the other three files for extra imports.
python2/test_typing.py
Outdated
subprocess.check_output('python -OO {}'.format(file_path), | ||
stderr=subprocess.STDOUT, | ||
shell=True) | ||
except: |
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.
Bare except is bad style. It can catch something unrelated, I was talking about only removing as e
part, since it was not used.
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.
Indeed. I will add it back immediately.
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! LGTM.
Issue #524 summary:
Running any script that imports typing_extensions with the -OO flag will raise an AttributeError.
Expected behavior:
Files should be able to import typing_extensions even if they're being ran with the -OO flag.
Actual behavior:
Raises the attribute error seen below because
Protocol.__doc__
is a NoneType when the -OO flag is used, and therefore has no attribute .format.Steps to recreate the error:
python setup.py install
for /typing/setup.py)python setup.py install
for /typing/typing_extensions/setup.py)python -OO
) and then try to import typing_extensions.Alternative steps to recreate the error:
python -OO test_typing_extensions.py
)The fix:
During running the tests, we can see that the problem originates from line 985 in /typing/typing_extensions/typing_extensions.py:
Placing a simple if-check to see whether Protocol.doc is not None around this piece of code avoids trying to call .format on a Nonetype.
Testing instructions:
In order to confirm whether the issue has been resolved, we can take the following steps.
python setup.py install
for /typing/setup.py).python setup.py install
for /typing/typing_extensions/setup.py).python -OO
) and then try to import typing_extensions.AND
python -OO test_typing_extensions.py
)python test_typing_extensions.py
)Output from testing (just the test_typing_extensions.py):
Request: