Skip to content
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

Refactor testpep561 and add test to address #5767 #5782

Merged
merged 22 commits into from
Oct 17, 2018

Conversation

chrisphilip322
Copy link
Contributor

I took some liberties while refactoring this to more fit my personal style and hopefully make more readable/extensible. I also added test cases for all the edge cases I found and filed in #5758; including a test case for which #5767 was filed.

I understand this is a pretty big change to this file and I am open to redoing it if its not popular.

@gvanrossum
Copy link
Member

Let's make sure this catches #5784

@gvanrossum
Copy link
Member

I would very much like to use these tests to prove that I've fixed #5784 (rather than just manually running the example shown there). But for that to happen this would probably have to be brought back to minimally invasive form -- or at least it would have to pass the tests on AppVeyor.

@chrisphilip322
Copy link
Contributor Author

Woops sorry, I'm moving too fast. I just saw I got an error and commited it. I'll work on actually repro'ing now that I've properly read the issue.

@chrisphilip322
Copy link
Contributor Author

Build failures so far are because of #5784. Right now, I am not really sure what the test should actually look like but for now it reproduces the issue at least, I will make a better test once the issue gets fixed.

@gvanrossum
Copy link
Member

See if the one-line fix in #5785 (latest version) fixes it.

@chrisphilip322
Copy link
Contributor Author

#5785 worked locally

Copy link
Collaborator

@ethanhs ethanhs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't claim to fully understand the issue in the 0.640 release yet (I will finally have time to look at it later today) but I don't think the C-extension complexity is needed. While in the original report it was an issue with the C-extension in asyncio, we also got a report with a normal Python module. Since this adds a fair amount of complexity, perhaps we could do something a bit simpler?

@chrisphilip322
Copy link
Contributor Author

@ethanhs could you share a link to the repro that doesn't use c extensions?

@gvanrossum
Copy link
Member

I've got a hunch that what you need to repro the issue is an installed package with a py.typed marker, and an import of a non-existent submodule of that package with a # type: ignore on the import. See the repro in #5784 -- since mypy doesn't see the C extension it doesn't matter whether it's installed or not.

I think that you have to install at least something like pkg/mod.py and inside that do from pkg.other import blah # type: ignore.

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some style comments, and a suggestion on how to avoid having to compile C code (which will make the tests fail on machines where the user hasn't installed a C compiler -- these days all too common).

On my machine (update: a Mac) test_typedpkg_editable() fails consistently, as follows:

Traceback (most recent call last):
  File "/Users/guido/src/mypy/mypy/test/testpep561.py", line 280, in test_typedpkg_editable
    venv_dir=venv_dir,
  File "/Users/guido/src/mypy/mypy/test/testpep561.py", line 123, in check_mypy_run
    assert out == self.build_msg(*expected_out), err
AssertionError: 
assert "/var/folders...pe is 'Any'\n" == "/var/folders/...ltins.str]'\n"
  - /var/folders/63/czkyq6090dd0t157zhx54xvhrdlybt/T/tmpo6_mhk_f/test_program.py:2: error: Cannot find module named 'typedpkg.sample'
  - /var/folders/63/czkyq6090dd0t157zhx54xvhrdlybt/T/tmpo6_mhk_f/test_program.py:2: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
  - /var/folders/63/czkyq6090dd0t157zhx54xvhrdlybt/T/tmpo6_mhk_f/test_program.py:3: error: Cannot find module named 'typedpkg'
  - /var/folders/63/czkyq6090dd0t157zhx54xvhrdlybt/T/tmpo6_mhk_f/test_program.py:5: error: Revealed type is 'Any'
  ?                                                                                                          ^ ^
  + /var/folders/63/czkyq6090dd0t157zhx54xvhrdlybt/T/tmpo6_mhk_f/test_program.py:5: error: Revealed type is 'builtins.tuple[builtins.str]'
  ?                                                                                                          ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^

(Also, these tests still take way too long to run. But I understand that running pip install is just slow...)


class NamespaceProgramImportStyle(Enum):
from_import = """\
from typedpkg_nested.nested_package.nested_module import nested_func
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dislike having those long module names. If you give each of them names of 3-5 letters it will become more readable (and you won't have to break long lines with \ below). Also a comment may be in order explaining why some things must go together on one line (IIUC it's so that the line numbers in the error messages are consistent?)

self.namespace_msg_int_bool = (
'{0}:9: error: Argument 1 to "alpha_func" has incompatible type "int"; '
'expected "bool"\n'.format(self.namespace_tempfile))
self.simple_example_program = ExampleProgram(SIMPLE_PROGRAM)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These variable names are all too long -- when skimming all I see is blah_blah_blah_blah. I don't think they all need to end in _example_program, and you can abbreviate namespace as ns.

******************************************************************/
#include <Python.h>

// ot ForbesFunction 1: A simple 'hello world' function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ot"?

name='typedpkg_c_ext',
version='1.0',
packages=['typedpkg_c_ext'],
ext_modules=[Extension('typedpkg_c_ext.hello', ['hello.c'])],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you can just delete this line (and the file hello.c) and the test works just as well. (Verified by removing the isdir() check from modulefinder.c line 124.)

@gvanrossum
Copy link
Member

There's something else missing. I patched this in, and then put an early return in _update_ns_ancestors() in modulefinder.py. This should simulate not fixing part two of #5758, notably https://github.com/python/mypy/pull/5762/commits (with an insightful review comment that I ignored).

But all pep561 tests still pass with that change (except test_typedpkg_editable() still fails). So it looks like the requested test still doesn't exist...

@chrisphilip322
Copy link
Contributor Author

I reorganized the test files so there isn't as much overlap with the test packages and made names in general shorter. I removed the c extensions test package because the repro can be done without it; and I made sure that the #5767 case is covered.

Side Note: I am expecting the tests to fail because it looks like there is repeated warning output in some cases.

@gvanrossum
Copy link
Member

But most tests are failing in the install phase -- is that also expected?

What warnings are you expecting exactly?

@chrisphilip322
Copy link
Contributor Author

I was reading the pytest output wrong, tests should pass now.

@gvanrossum
Copy link
Member

I still get the failure on test_typedpkg_editable(). Any insight on how I should debug this?

@ilevkivskyi
Copy link
Member

I still get the failure on test_typedpkg_editable(). Any insight on how I should debug this?

Are you under a virtualenv on a Mac? If yes, then this is not new, it fails since some time.

@ilevkivskyi
Copy link
Member

I am seeing this:

E           AssertionError: 
E           assert "/var/folders...pe is 'Any'\n" == "/var/folders/...ltins.str]'\n"
E             Skipping 61 identical leading characters in diff, use -v to show
E             + simple.py:5: error: Revealed type is 'builtins.tuple[builtins.str]'
E             - simple.py:2: error: Cannot find module named 'typedpkg.sample'
E             - /var/folders/ff/8tg5kw8x3jg3z9cw0359hllxss39wp/T/tmph7q_wh1f/simple.py:2: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
E             - /var/folders/ff/8tg5kw8x3jg3z9cw0359hllxss39wp/T/tmph7q_wh1f/simple.py:3: error: Cannot find module named 'typedpkg'
E             - /var/folders/ff/8tg5kw8x3jg3z9cw0359hllxss39wp/T/tmph7q_wh1f/simple.py:5: error: Revealed type...
E             
E             ...Full output truncated (1 line hidden), use '-vv' to show

for few month, but I have never had time to fix it.

@gvanrossum
Copy link
Member

Yeah, that's what I get too (the traceback I reported is about the same). And yes, I am under a venv.

@ilevkivskyi
Copy link
Member

ilevkivskyi commented Oct 14, 2018

I think this is an issue with the test infrastructure, since the same scenario works fine with installed mypy. A natural guess is that something goes wrong because this test creates a new virtual environment that probably conflicts somehow with the current environment.

@gvanrossum
Copy link
Member

Hm, I should really leave this alone, but I investigated a bit more and found that when an outer venv is already active, the line self.install_package('typedpkg', python_executable, editable=True) installs the typedpkg.egg-link file in the outer venv. And apparently the test cannot find it there. Possibly this is a pip issue -- or possibly the code in install_package() needs something extra to convince pip to use the inner venv.

@gvanrossum
Copy link
Member

One more internal monologue and then I'll let it go. :-)

I added -v to the pip command and the crucial bits seem to be this:

Installing collected packages: typedpkg
  Found existing installation: typedpkg 0.1
    Not uninstalling typedpkg at /Users/guido/src/mypy/test-data/packages/typedpkg, outside environment /var/folders/63/czkyq6090dd0t157zhx54xvhrdlybt/T/tmp5ov0t1ad/bin/..
    Can't uninstall 'typedpkg'. No files were found to uninstall.

There's other verbose output before and after this, but in a successful run, instead of this I see:

Installing collected packages: typedpkg
  Found existing installation: typedpkg 0.1
    Uninstalling typedpkg-0.1:
      Created temporary directory: /private/var/folders/63/czkyq6090dd0t157zhx54xvhrdlybt/T/pip-uninstall-5hfyyz5b
      Removing file or directory /Users/guido/src/mypy/vv/lib/python3.7/site-packages/typedpkg.egg-link
      Removing pth entries from /Users/guido/src/mypy/vv/lib/python3.7/site-packages/easy-install.pth:
      Removing entry: /Users/guido/src/mypy/test-data/packages/typedpkg
      Successfully uninstalled typedpkg-0.1

Additional notes:

  • When I manually create two venvs (v1 and v2), activate v1, and run v2/bin/pip install -e .../typedpkg in the other, the egg-link file gets created in the right place.
  • If I don't activate v1 but run v1/bin/python3 -m pytest ... (so effectively v2 is created by the test program) the problem still appears.
  • I added another test, test_typedpkg_egg_editable(), which uses use_pip=False, editable=True (i.e. invoking setup.py develop directly) and that one passed.

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. If Ethan agrees this can be merged!

python_executable,
expected_out=self.msg_dne + self.msg_list,
[SimpleMsg.msg_dne,
SimpleMsg.msg_list],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I don't care much for splitting this line -- the whole list easily fits.)

Copy link
Collaborator

@ethanhs ethanhs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two suggestions, but otherwise seems fine to me.
Thank you for working on this!

self._temp_dir = None # type: Optional[tempfile.TemporaryDirectory[str]]
self._full_fname = ''

def init(self) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: rename to create? init doesn't really tell me what it is doing, create implies it is doing setup work and creating the test case.

assert err == expected_err, out
assert returncode == expected_returncode, returncode
finally:
class NSImportStyle(Enum):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad to see these going into Enums. :)

return _NAMESPACE_PROGRAM.format(import_style=import_style.value)


class ExampleProg(object):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change this to just Program and change the suffixes below to self.simple_ep to self.simple_prog or something? ep is not a straightforward mnemonic (at least to me).

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll merge this now. Thank you for this! (And thanks Ethan for the review.)

@gvanrossum gvanrossum merged commit c0f357c into python:master Oct 17, 2018
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