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

sage -t: Do not run pytest on individual Python files unless they match the pytest file pattern #31924

Closed
mkoeppe opened this issue Jun 7, 2021 · 128 comments

Comments

@mkoeppe
Copy link
Member

mkoeppe commented Jun 7, 2021

sage -t is broken since #31003/#31103 because

  • pytest is configured to look for methods prefixed with test_ and treats them as pytest test functions/methods, which are then executed. However, sage's code base contains some functions in its codebase that match this pattern without being pytests.
  • pytest (Add minimal pytest configuration #31003) is configured to only discover *_test.py files; but if one uses sage -t with file arguments, this will override it and lead to many errors.
$ ./sage -t  src/sage/databases/*.py 
too many failed tests, not using stored timings
Running doctests with ID 2021-06-07-11-04-14-3c1f8784.
Using --optional=4ti2,bliss,build,database_knotinfo,dochtml,e_antic,homebrew,jupymake,latte_int,lidia,lrslib,normaliz,pip,sage,sage_spkg
Doctesting 16 files.
sage -t --random-seed=0 src/sage/databases/__init__.py
    [0 tests, 0.00 s]
sage -t --random-seed=0 src/sage/databases/all.py
    [5 tests, 0.10 s]
sage -t --random-seed=0 src/sage/databases/conway.py
    [42 tests, 0.10 s]
sage -t --random-seed=0 src/sage/databases/cremona.py
    [133 tests, 0.31 s]
sage -t --random-seed=0 src/sage/databases/cunningham_tables.py
    [0 tests, 0.00 s]
sage -t --random-seed=0 src/sage/databases/db_class_polynomials.py
    [7 tests, 0.01 s]
sage -t --random-seed=0 src/sage/databases/db_modular_polynomials.py
    [13 tests, 0.01 s]
sage -t --random-seed=0 src/sage/databases/findstat.py
    [122 tests, 0.25 s]
sage -t --random-seed=0 src/sage/databases/jones.py
    [8 tests, 0.05 s]
sage -t --random-seed=0 src/sage/databases/knotinfo_db.py
    [97 tests, 1.80 s]
sage -t --random-seed=0 src/sage/databases/odlyzko.py
    [0 tests, 0.00 s]
sage -t --random-seed=0 src/sage/databases/oeis.py
    [134 tests, 0.91 s]
sage -t --random-seed=0 src/sage/databases/sloane.py
    [0 tests, 0.00 s]
sage -t --random-seed=0 src/sage/databases/sql_db.py
    [293 tests, 0.27 s]
sage -t --random-seed=0 src/sage/databases/stein_watkins.py
    [12 tests, 0.01 s]
sage -t --random-seed=0 src/sage/databases/symbolic_data.py
    [0 tests, 0.00 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 4.6 seconds
    cpu time: 3.9 seconds
    cumulative wall time: 3.8 seconds
============================================================================== test session starts ===============================================================================
platform darwin -- Python 3.9.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /Users/mkoeppe/s/sage/sage-rebasing/worktree-gcc11/src, configfile: tox.ini
collected 0 items / 7 errors                                                                                                                                                     

===================================================================================== ERRORS =====================================================================================
_____________________________________________________________________ ERROR collecting sage/databases/all.py _____________________________________________________________________
ImportError while importing test module '/Users/mkoeppe/s/sage/sage-rebasing/worktree-gcc11/src/sage/databases/all.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
src/sage/databases/all.py:51: in <module>
    from .sql_db import SQLQuery, SQLDatabase
E   ImportError: attempted relative import with no known parent package
_____________________________________________________________________ ERROR collecting sage/databases/all.py _____________________________________________________________________
ImportError while importing test module '/Users/mkoeppe/s/sage/sage-rebasing/worktree-gcc11/src/sage/databases/all.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
src/sage/databases/all.py:51: in <module>
    from .sql_db import SQLQuery, SQLDatabase
E   ImportError: attempted relative import with no known parent package
___________________________________________________________________ ERROR collecting sage/databases/cremona.py ___________________________________________________________________
ImportError while importing test module '/Users/mkoeppe/s/sage/sage-rebasing/worktree-gcc11/src/sage/databases/cremona.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
src/sage/databases/cremona.py:52: in <module>
    from .sql_db import SQLDatabase, verify_column
E   ImportError: attempted relative import with no known parent package
____________________________________________________________ ERROR collecting sage/databases/db_class_polynomials.py _____________________________________________________________
ImportError while importing test module '/Users/mkoeppe/s/sage/sage-rebasing/worktree-gcc11/src/sage/databases/db_class_polynomials.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
src/sage/databases/db_class_polynomials.py:14: in <module>
    from .db_modular_polynomials import _dbz_to_integers
E   ImportError: attempted relative import with no known parent package
__________________________________________________________________ ERROR collecting sage/databases/findstat.py ___________________________________________________________________
src/sage/databases/findstat.py:329: in <module>
    class FindStat(UniqueRepresentation, SageObject):
sage/misc/nested_class.pyx:318: in sage.misc.nested_class.NestedClassMetaclass.__init__
    ???
E   KeyError: 'findstat'
_________________________________________________________________ ERROR collecting sage/databases/knotinfo_db.py _________________________________________________________________
src/sage/databases/knotinfo_db.py:330: in <module>
    class KnotInfoDataBase(SageObject, UniqueRepresentation):
sage/misc/nested_class.pyx:318: in sage.misc.nested_class.NestedClassMetaclass.__init__
    ???
E   KeyError: 'knotinfo_db'
____________________________________________________________________ ERROR collecting sage/databases/oeis.py _____________________________________________________________________
src/sage/databases/oeis.py:651: in <module>
    class OEISSequence(SageObject, UniqueRepresentation):
sage/misc/nested_class.pyx:318: in sage.misc.nested_class.NestedClassMetaclass.__init__
    ???
E   KeyError: 'oeis'
============================================================================ short test summary info =============================================================================
ERROR src/sage/databases/all.py
ERROR src/sage/databases/all.py
ERROR src/sage/databases/cremona.py
ERROR src/sage/databases/db_class_polynomials.py
ERROR src/sage/databases/findstat.py - KeyError: 'findstat'
ERROR src/sage/databases/knotinfo_db.py - KeyError: 'knotinfo_db'
ERROR src/sage/databases/oeis.py - KeyError: 'oeis'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 7 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Related report in https://groups.google.com/g/sage-devel/c/SE_A2Jw5Kko/m/KQpA9GbjBQAJ:

=============================================================== ERRORS
================================================================
_________________________________________ ERROR collecting
sage/structure/sage_object_test.py
_________________________________________
ImportError while importing test module
'/home/john/sage/src/sage/structure/sage_object_test.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
src/sage/structure/sage_object_test.py:3: in <module>
from .sage_object import SageObject
E ImportError: attempted relative import with no known parent package
======================================================= short test
summary info =======================================================
ERROR src/sage/structure/sage_object_test.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error
during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

In this ticket, we fix it by passing names of regular files to pytest only if they match the pytest pattern (ending with _test.py).

(The dependency #32975 renamed the files in the Sage sources that used this naming scheme but were not pytest files.)

Example:

$ ./sage -tp src/sage/numerical/backends src/sage/symbolic/expression.pyx src/sage/manifolds/differentiable/symplectic_form_test.py 
too many failed tests, not using stored timings
Running doctests with ID 2022-03-22-11-30-32-fd280468.
Using --optional=4ti2,buckygen,ccache,cryptominisat,debugpy,e_antic,gap_packages,homebrew,igraph,jupymake,latte_int,libsemigroups,lidia,lrslib,meataxe,normaliz,pip,polytopes_db_4d,pynormaliz,sage,sage_spkg
Features to be detected: 4ti2,benzene,bliss,buckygen,conway_polynomials,csdp,database_cremona_ellcurve,database_cremona_mini_ellcurve,database_jones_numfield,database_knotinfo,dvipng,graphviz,imagemagick,jupymake,kenzo,latte_int,lrslib,mcqd,meataxe,nauty,palp,pandoc,pdf2svg,pdftocairo,plantri,polytopes_db,polytopes_db_4d,pynormaliz,python_igraph,rubiks,sage.combinat,sage.geometry.polyhedron,sage.graphs,sage.groups,sage.plot,sage.rings.number_field,sage.rings.padics,sage.rings.real_double,sage.symbolic,sage_numerical_backends_coin,sagemath_doc_html,sphinx,tdlib
Sorting sources by runtime so that slower doctests are run first....
Doctesting 27 files using 8 threads.
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_backend.pxd
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/interactivelp_backend.pxd
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/generic_backend.pxd
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_graph_backend.pxd
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/matrix_sdp_backend.pxd
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/cvxopt_sdp_backend.pyx
    [52 tests, 0.08 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/generic_sdp_backend.pxd
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/matrix_sdp_backend.pyx
    [87 tests, 0.14 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_graph_backend.pyx
    [193 tests, 0.17 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/ppl_backend.pyx
    [221 tests, 0.25 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/logging_backend.py
    [45 tests, 0.05 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_exact_backend.pxd
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/generic_sdp_backend.pyx
    [37 tests, 0.07 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/manifolds/differentiable/symplectic_form_test.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/interactivelp_backend_test.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/cvxopt_backend.pyx
    [25 tests, 0.05 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_exact_backend.pyx
    [24 tests, 0.03 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/cvxopt_backend_test.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/ppl_backend_test.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_backend_test.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/__init__.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/generic_backend_test.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_exact_backend_test.py
    [0 tests, 0.00 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/generic_backend.pyx
    [96 tests, 0.59 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/interactivelp_backend.pyx
    [266 tests, 3.09 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/numerical/backends/glpk_backend.pyx
    [592 tests, 3.08 s]
sage -t --random-seed=156872034187085869352407545599456758260 src/sage/symbolic/expression.pyx
    [3070 tests, 31.83 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 32.6 seconds
    cpu time: 39.3 seconds
    cumulative wall time: 39.4 seconds
Features detected for doctesting: sage.rings.number_field
============================================================================================================ test session starts ============================================================================================================
platform darwin -- Python 3.7.8, pytest-7.1.1, pluggy-1.0.0
rootdir: /Users/mkoeppe/s/sage/sage-rebasing/worktree-gcc11/src, configfile: tox.ini
collected 32 items                                                                                                                                                                                                                          

src/sage/numerical/backends/cvxopt_backend_test.py ..                                                                                                                                                                                 [  6%]
src/sage/numerical/backends/glpk_backend_test.py ..                                                                                                                                                                                   [ 12%]
src/sage/numerical/backends/glpk_exact_backend_test.py ..                                                                                                                                                                             [ 18%]
src/sage/numerical/backends/interactivelp_backend_test.py ..                                                                                                                                                                          [ 25%]
src/sage/numerical/backends/ppl_backend_test.py ..                                                                                                                                                                                    [ 31%]
src/sage/manifolds/differentiable/symplectic_form_test.py ......................                                                                                                                                                      [100%]

=======================================================================================

CC: @tobiasdiez @soehms @JohnCremona @dimpase @saraedum @isuruf @tscrim

Component: doctest framework

Author: Matthias Koeppe

Branch/Commit: 1214e0c

Reviewer: Sebastian Oehms

Issue created by migration from https://trac.sagemath.org/ticket/31924

@mkoeppe mkoeppe added this to the sage-9.4 milestone Jun 7, 2021
@mkoeppe

This comment has been minimized.

@soehms
Copy link
Member

soehms commented Jul 2, 2021

comment:3

It seems that there is no way to tell pytest to ignore non matching files from the argument list on throwing these error messages.

So, is there anything standing against just doing it like this?

diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests
index 16d3295..e852853 100755
--- a/src/bin/sage-runtests
+++ b/src/bin/sage-runtests
@@ -143,15 +143,16 @@ if __name__ == "__main__":
     DC = DocTestController(options, args)
     err = DC.run()

-    try:
-        exit_code_pytest = 0
-        import pytest
-        pytest_options = ["--import-mode", "importlib"]
-        if options.verbose:
-            pytest_options.append("-v")
-        exit_code_pytest = pytest.main(pytest_options + args)
-    except ModuleNotFoundError:
-        print("Pytest is not installed, skip checking tests that rely on it.")
+    exit_code_pytest = 0
+    if not args:
+        try:
+            import pytest
+            pytest_options = ["--import-mode", "importlib"]
+            if options.verbose:
+                pytest_options.append("-v")
+            exit_code_pytest = pytest.main(pytest_options + args)
+        except ModuleNotFoundError:
+            print("Pytest is not installed, skip checking tests that rely on it.")

@mkoeppe
Copy link
Member Author

mkoeppe commented Jul 2, 2021

comment:4

Directory arguments work fine, it's just regular file arguments that cause the trouble.

@soehms
Copy link
Member

soehms commented Jul 3, 2021

comment:5

Replying to @mkoeppe:

Directory arguments work fine, it's just regular file arguments that cause the trouble.

I see! I will have a look at it next week!

@tobiasdiez
Copy link
Contributor

comment:6

I think the problem is that in pytest.main(pytest_options + args) the argument -t src/sage/databases/*.py is appended, but the correct format for pytest to only test a single file would be without the -t, i.e. pytest src/sage/databases/*.py should work.

@soehms
Copy link
Member

soehms commented Jul 6, 2021

comment:7

Replying to @tobiasdiez:

I think the problem is that in pytest.main(pytest_options + args) the argument -t src/sage/databases/*.py is appended, but the correct format for pytest to only test a single file would be without the -t, i.e. pytest src/sage/databases/*.py should work.

I cannot verify this on my environment:

~/devel/sage$ ./local/bin/pytest src/sage/databases/knotinfo_db.py
======================================================================================================================================== test session starts ========================================================================================================================================
platform linux -- Python 3.9.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /home/sebastian/devel/sage/src, configfile: tox.ini
collected 0 items / 1 error

============================================================================================================================================== ERRORS ===============================================================================================================================================
__________________________________________________________________________________________________________________________ ERROR collecting sage/databases/knotinfo_db.py ___________________________________________________________________________________________________________________________
ImportError while importing test module '/home/sebastian/devel/sage/src/sage/databases/knotinfo_db.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
local/lib/python3.9/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
src/sage/databases/knotinfo_db.py:31: in <module>
    from sage.structure.sage_object import SageObject
src/sage/structure/__init__.py:2: in <module>
    import sage.structure.element
E   ModuleNotFoundError: No module named 'sage.structure.element'
====================================================================================================================================== short test summary info ======================================================================================================================================
ERROR src/sage/databases/knotinfo_db.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
========================================================================================================================================= 1 error in 0.29s ==========================================================================================================================================

@tobiasdiez
Copy link
Contributor

comment:8

Okay, then I misread the exception message. Thanks for the investigation.

So the problem is that pytest doesn't find the compiled cython modules. I think the common advice is to use the editable install. Another solution that might work is to install and run pytest from the same virtual environment where sage is installed in. Finally, there are some hacks to add the sage path in sys.path as outlined here: pytest-dev/pytest#2421 (comment)

@soehms
Copy link
Member

soehms commented Jul 7, 2021

comment:9

Replying to @tobiasdiez:

So the problem is that pytest doesn't find the compiled cython modules.

Why does it find them for directory arguments?

I think the common advice is to use the editable install. Another solution that might work is to install and run pytest from the same virtual environment where sage is installed in.

How can we achieve one of these options?

Finally, there are some hacks to add the sage path in sys.path as outlined here: https://github.com/pytest- dev/pytest/issues/2421#issuecomment-403724503

I don't think that it is worth to do that (citation from the comment: And do not forget to remove this before publishing to PyPI).

@tobiasdiez
Copy link
Contributor

comment:10

Replying to @soehms:

Replying to @tobiasdiez:

So the problem is that pytest doesn't find the compiled cython modules.

Why does it find them for directory arguments?

Good question. I have no idea. Maybe the directory argument is in a wrong format so that pytest actually doesn't try to load any test files?

I think the common advice is to use the editable install. Another solution that might work is to install and run pytest from the same virtual environment where sage is installed in.

How can we achieve one of these options?

The editable install is possible since #31377 and should just work. I'm not familiar enough with the "usual" sage build to be able to recommend a solution that works with it. In the end, you need to specify the sage install directory as part of the PYTHON_PATH so that pytest is able to find the compiled cython modules. Maybe @mkoeppe has an idea.

@mkoeppe
Copy link
Member Author

mkoeppe commented Jul 7, 2021

comment:11

Replying to @soehms:

Replying to @tobiasdiez:

So the problem is that pytest doesn't find the compiled cython modules.

Why does it find them for directory arguments?

I don't think it does. What is happening, if I'm not mistaken, is simply that pytest, as configured in src/tox.ini, only runs for Python files matching the pattern *_test.py; modified with the exclusions declared in src/conftest.py. When you pass the names of individual Python files to it, the pattern matching is overridden.

Hence my suggestion of a workaround -- filter out Python file name arguments before passing them to pytest when invoked via sage -t.

@tobiasdiez
Copy link
Contributor

comment:12

Yes, that would work as a workaround. However, the underlying problem is still that pytest cannot find cython modules and I think this should be fixed as well (since otherwise you cannot have a pytest test file that has similar imports as knotinfo_db.py)

@mkoeppe
Copy link
Member Author

mkoeppe commented Jul 7, 2021

comment:13

Replying to @tobiasdiez:

the underlying problem is still that pytest cannot find cython modules and I think this should be fixed as well (since otherwise you cannot have a pytest test file that has similar imports as knotinfo_db.py)

Yes, I agree, but that would be another ticket, as this is not "critical" for Sage 9.4.

@soehms
Copy link
Member

soehms commented Jul 8, 2021

comment:14

Replying to @tobiasdiez:

The editable install is possible since #31377 and should just work. I'm not familiar enough with the "usual" sage build to be able to recommend a solution that works with it. In the end, you need to specify the sage install directory as part of the PYTHON_PATH so that pytest is able to find the compiled cython modules. Maybe @mkoeppe has an idea.

After building Sage with ./configure --enable-editable the issue still shows. What could I have done wrong?

@soehms
Copy link
Member

soehms commented Jul 8, 2021

comment:15

Replying to @mkoeppe:

Replying to @soehms:

Replying to @tobiasdiez:

So the problem is that pytest doesn't find the compiled cython modules.

Why does it find them for directory arguments?

I don't think it does. What is happening, if I'm not mistaken, is simply that pytest, as configured in src/tox.ini, only runs for Python files matching the pattern *_test.py; modified with the exclusions declared in src/conftest.py. When you pass the names of individual Python files to it, the pattern matching is overridden.

First, I thought the same. But, the following output made me doubt: collected 0 items / 1 error.

Hence my suggestion of a workaround -- filter out Python file name arguments before passing them to pytest when invoked via sage -t.

Passing an empty argument list, causes an error, as well:

:~/devel/sage$ sage -t --new
Running doctests with ID 2021-07-08-09-15-06-93fe9beb.
Git branch: develop
Using --optional=build,debian,dochtml,pip,sage,sage_spkg
Doctesting files changed since last git commit
No files to doctest
======================================================================================================================================== test session starts ========================================================================================================================================
platform linux -- Python 3.9.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /home/sebastian/devel/sage
collected 0 items / 1 error

============================================================================================================================================== ERRORS ===============================================================================================================================================
___________________________________________________________________________________________________________________________________ ERROR collecting test session ___________________________________________________________________________________________________________________________________
local/lib/python3.9/site-packages/IPython/conftest.py:9: in <module>
    from .testing import tools
E   ImportError: attempted relative import with no known parent package
====================================================================================================================================== short test summary info ======================================================================================================================================
ERROR  - ImportError: attempted relative import with no known parent package

The same output shows with ./local/bin/pytest --import-mode importlib

@mkoeppe
Copy link
Member Author

mkoeppe commented Jul 8, 2021

comment:16

Replying to @soehms:

Passing an empty argument list, causes an error, as well

OK then, that's another case in which sage -t should not invoke pytest.

@soehms
Copy link
Member

soehms commented Jul 12, 2021

comment:17

I would implement the workaround suggested in comment 11. But at the moment I'm sticking at the following question: What is the best way to share the pattern *_test.py between src/tox.ini and sage-runtests?

@mkoeppe mkoeppe modified the milestones: sage-9.4, sage-9.5 Aug 11, 2021
@tobiasdiez
Copy link
Contributor

comment:21

Thinking about this again, I was wondering what is the desired behavior of the -t <files> argument?
The following seems reasonable to me:

  • If <files> is a folder, then test all "testable" files in that folder. Here "testable" takes e.g. the file extension (py, rst) into account; and also the pre-defined filter for pytest (_test.py ending).
  • If <files> is a path to a file (or a glob), then test exactly those files without taking the above "testable" criteria into account. One might argue that one should also intersect with "testable" but I guess its better to trust the user that he knows why he wants exactly these files to be tested.

This also seems to be the default behavior of pytest (i.e. run pytest <files> with either a folder or a fixed path). It also seems to be that sage-runtests is behaving exactly like this, so I don't know if the test discovery should really be changed.

According to this point of view, the reported error is not really a problem with the pytest test discovery but more so an issue with loading these files as modules. If the import would work, pytest would try to find pytest tests in these files, which don't exist, so it would simply not collect anything.

@soehms
Copy link
Member

soehms commented Nov 4, 2021

comment:22

Replying to @tobiasdiez:

According to this point of view, the reported error is not really a problem with the pytest test discovery but more so an issue with loading these files as modules. If the import would work, pytest would try to find pytest tests in these files, which don't exist, so it would simply not collect anything.

To you mean to replace relative import statements by absolute ones all over the source code? Would this solve the problem?

BTW: Did you note that the pytest call in sage-runtests is broken since 9.5.beta3 (see this comment in the according release management thread):

Traceback (most recent call last):
  File "/home/sebastian/devel/sage/src/bin/sage-runtests", line 159, in <module>
    exit_code_pytest = pytest.main(pytest_options + args)
TypeError: can only concatenate list (not "Namespace") to list

Probably this is due to #32332.

@tobiasdiez
Copy link
Contributor

comment:23

I don't have much experience with relative imports and namespace imports. But yes, converting relative imports to absolute ones should fix the issue.

@tornaria
Copy link
Contributor

comment:24

I get a doctest failure in src/sage/tests/cmdline.py that seems to be related.

sage -t --random-seed=156938138878576468116341825690522372403 src/sage/tests/cmdline.py
**********************************************************************
File "src/sage/tests/cmdline.py", line 325, in sage.tests.cmdline.test_executable
Failed example:
    ret
Expected:
    0
Got:
    4
**********************************************************************
File "src/sage/tests/cmdline.py", line 330, in sage.tests.cmdline.test_executable
Failed example:
    ret
Expected:
    0
Got:
    5
**********************************************************************
1 item had failures:
   2 of 221 in sage.tests.cmdline.test_executable
    [220 tests, 2 failures, 48.13 s]
----------------------------------------------------------------------

The second failure gets fixed after #32892 but not the first one.

Here's a standalone example of the issue:

$ cat my_script.sage                                             
# -*- coding: utf-8 -*-
'''This is a test file.
And I am its doctest'''
def my_add(a):
    '''
    Add 2 to a.

        EXAMPLES::

            sage: my_add(2)
            4
        '''
    return a + 2
$ ./sage -t my_script.sage ; echo $?                             
Running doctests with ID 2021-11-22-16-48-40-b731cf3e.
Git branch: develop
Using --optional=build,pip,sage,sage.geometry.polyhedron,sage.rings.real_double,sage_spkg,void
Doctesting 1 file.
sage -t --warn-long 36.1 --random-seed=215445574591070240478383051094230654766 my_script.sage
    [1 test, 0.00 s]
----------------------------------------------------------------------
All tests passed!
----------------------------------------------------------------------
Total time for all tests: 0.0 seconds
    cpu time: 0.0 seconds
    cumulative wall time: 0.0 seconds
============================================================================ test session starts =============================================================================
platform linux -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /usr/lib/sage-9.5.beta7
collected 0 items                                                                                                                                                            

=========================================================================== no tests ran in 0.00s ============================================================================
ERROR: not found: /usr/lib/sage-9.5.beta7/my_script.sage
(no name '/usr/lib/sage-9.5.beta7/my_script.sage' in any of [])

4

What I think is going on: pytest is called by

exit_code_pytest = pytest.main(pytest_options + args.filenames)

where args.filenames = ['my_script.sage']. But pytest is skipping my_script.sage since it doesn't match patterns *.py, *.txt or *.rst (or something like that). That's the reason for the "ERROR: not found" in there, and the error code is 4 (pytest command line usage error).

I don't know what's a proper way to fix this. Maybe filter out the list of files in args.filenames so that only the files that pytest likes get through (not *.sage, anyway). Warning: when args.filenames is not empty but it becomes empty after filtering, the call to pytest must be skipped otherwise pytest just tests everything recursively, which is not what we want.

@soehms
Copy link
Member

soehms commented Nov 30, 2021

comment:25

Replying to @tobiasdiez:

I don't have much experience with relative imports and namespace imports. But yes, converting relative imports to absolute ones should fix the issue.

Sounds like we should make a script that replaces all relative import statements by an absolute one (all over the source tree). Are we sure that there are no such import statement being intentional (by whatever reason)?

@soehms
Copy link
Member

soehms commented Nov 30, 2021

comment:26

Replying to @tornaria:

I don't know what's a proper way to fix this. Maybe filter out the list of files in args.filenames so that only the files that pytest likes get through (not *.sage, anyway). Warning: when args.filenames is not empty but it becomes empty after filtering, the call to pytest must be skipped otherwise pytest just tests everything recursively, which is not what we want.

What is the difference to the suggestion made in comment:11 ff? Do you have a hint to the question I asked in comment:17 ?

@mkoeppe
Copy link
Member Author

mkoeppe commented Mar 26, 2022

comment:112

Replying to @soehms:

LGTM. From my point of view this can get a positive review depending on how the fundamental discussion comes to an end.

There's no fundamental discussion happening here. It's not a question of "either-or", but a strategy of fixing now what can be fixed to get a high quality release 9.6, and doing the larger fixes when they are ready. In comment:78, comment:89, comment:90, etc. I have already explained how to adjust the change in this ticket when this work is done.

@soehms
Copy link
Member

soehms commented Mar 27, 2022

comment:113

Replying to @mkoeppe:

Replying to @soehms:

LGTM. From my point of view this can get a positive review depending on how the fundamental discussion comes to an end.

There's no fundamental discussion happening here. It's not a question of "either-or", but a strategy of fixing now what can be fixed to get a high quality release 9.6, and doing the larger fixes when they are ready. In comment:78, comment:89, comment:90, etc. I have already explained how to adjust the change in this ticket when this work is done.

I've seen that the discussion was about strategy. But obviously the strategy was not clarified completely and thus the discussion was not finished at that point. By your comment comment 109 and the new ticket #33572 the situation is improved, now.

The difficulty with this ticket is that it shades out a couple of issues Tobias is currently working on. I can understand that this was annoying. For example the bug treated in #33550 will not show any more in the way as it did before if this ticket is released.

Thus, we should work throughout all of these issues and find new test cases for them, now. Probably, the best way to do this is to use #33572.

@tobiasdiez
Copy link
Contributor

comment:114

Replying to @mkoeppe:

#33549 is now a dependency of the present ticket.

There's still more to be addressed in #33550, #33560, and #33561 in order to fix everything that is fixed by the present ticket.

All of which are ready for review.

@tobiasdiez
Copy link
Contributor

comment:115

Replying to @soehms:

The difficulty with this ticket is that it shades out a couple of issues Tobias is currently working on. I can understand that this was annoying. For example the bug treated in #33550 will not show any more in the way as it did before if this ticket is released.

Thus, we should work throughout all of these issues and find new test cases for them, now. Probably, the best way to do this is to use #33572.

I agree #33572 would be a good way to test. But as the discussion there shows running pytest somefile.py still needs a lot of work until it works because sage.all is not imported. On the other hand, sage -t takes care of this.

I hope #33550, #33560, and #33561 get reviewed before this ticket here is merged, since otherwise the reviewers have to revert the changes manually before running sage -t.

@tornaria
Copy link
Contributor

comment:116

May I suggest adding some switches to sage-runtests:

  • --skip-doctest: if given, the DocTestController run would be skipped
  • --skip-pytest: if given, the pytest run would be skipped

And maybe:

  • --pytest-all: if given, the filename filter implemented in this ticket would not be applied, so pytest would be run for all the given arguments

I think it would be quite useful (a) if I happen to have pytest installed and for some reason (maybe something is broken, perhaps because a bug in my system pytest, whatever) I prefer to skip pytest (b) if I want to actually test pytest (maybe I'm working on the pytest code) I may want to run pytest on different arguments without having to wait for doctest (c) want to run pytest on some file not matching the pattern.

All of these are easy to acomplish by trivial patching of sage-runtests but it's much more convenient to be able to get these different behaviours with an unchanged script.

@mkoeppe
Copy link
Member Author

mkoeppe commented Mar 27, 2022

comment:117

Thanks for the review.

@mkoeppe
Copy link
Member Author

mkoeppe commented Mar 27, 2022

comment:118

Replying to @tornaria:

May I suggest adding some switches to sage-runtests

Separate ticket

@GMS103
Copy link
Member

GMS103 commented Mar 27, 2022

comment:119

This is on Apple Silicon M1 Macs with Homebrew up to date, both macOS 11.6.5 (Big Sur) with Xcode 13.2.1 and macOS 12.3 (Monterey) with Xcode 13.3.

SageMath 9.6.beta6 together with this ticket #31924 and nothing else:
after make and make pytest, make ptestlong gives

**********************************************************************
File "src/sage/tests/cmdline.py", line 311, in sage.tests.cmdline._test_executable
Failed example:
    (out, err, ret) = test_executable(["sage", "-t", script])
Exception raised:
    Traceback (most recent call last):
      File "/Users/sagemath/SageMath/Git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/doctest/forker.py", line 695, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/Users/sagemath/SageMath/Git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/doctest/forker.py", line 1093, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.tests.cmdline._test_executable[107]>", line 1, in <module>
        (out, err, ret) = test_executable(["sage", "-t", script])
    NameError: name 'test_executable' is not defined
**********************************************************************
File "src/sage/tests/cmdline.py", line 314, in sage.tests.cmdline._test_executable
Failed example:
    out.find("All tests passed!") >= 0
Expected:
    True
Got:
    False
**********************************************************************

Am I doing something wrong?

BTW, I am at a loss with all the tickets mentioned here. Some would not merge with this one.

@mkoeppe
Copy link
Member Author

mkoeppe commented Mar 27, 2022

comment:120

That's fixed in the latest version of #33549 - I haven't merged that here.

@GMS103
Copy link
Member

GMS103 commented Mar 28, 2022

comment:121

FWIW, positive review for SageMath 9.6.beta6 plus #31924 and #33549 plus make pytest on Apple Silicon M1 Macs with Homebrew up to date, both macOS 11.6.5 (Big Sur) with Xcode 13.2.1 and macOS 12.3 (Monterey) with Xcode 13.3.

@soehms
Copy link
Member

soehms commented Mar 28, 2022

comment:122

Sorry for the lack of attention!

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Mar 30, 2022

Changed commit from 8139e09 to 1214e0c

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Mar 30, 2022

Branch pushed to git repo; I updated commit sha1 and set ticket back to needs_review. This was a forced push. New commits:

1414bc8src/bin/sage-runtests: Do not run pytest on individual Python files unless they match the pytest file pattern
89c7a8esrc/bin/sage-runtests: Do not run pytest on *.pyx, *.pxd, *.rst, etc.
1214e0csrc/bin/sage-runtests: Use os.path.isfile, fix ticket number in comment

@mkoeppe
Copy link
Member Author

mkoeppe commented Mar 30, 2022

Changed dependencies from #32975, #33549 to none

@mkoeppe
Copy link
Member Author

mkoeppe commented Mar 30, 2022

comment:124

Rebased on 9.6.beta6, away from #33549

@vbraun
Copy link
Member

vbraun commented Apr 2, 2022

@vbraun vbraun closed this as completed in e39a3a2 Apr 2, 2022
vbraun pushed a commit that referenced this issue Aug 5, 2023
    
<!-- ^^^^^
Please provide a concise, informative and self-explanatory title.
Don't put issue numbers in there, do this in the PR body below.
For example, instead of "Fixes #1234" use "Introduce new method to
calculate 1+1"
-->
<!-- Describe your changes here in detail -->

This fixes the failure seen, for example,

https://github.com/sagemath/sage/actions/runs/5678761729/job/15389749593
?pr=35991

Note that the last failure message
```
local/var/lib/sage/venv-python3.8/lib/python3.8/site-
packages/matplotlib/tests/__init__.py:6: in <module>
    raise IOError(
E   OSError: The baseline image directory does not exist. This is most
likely because the test data is not installed. You may need to install
matplotlib from source to get the test data.
=========================== short test summary info
============================
ERROR  - OSError: The baseline image directory does not exist. This is
most likely because the test data is not installed. You may need to
install matplotlib from source to get the test data.
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection
!!!!!!!!!!!!!!!!!!!!
============================== 1 error in 12.78s
===============================
Error: Process completed with exit code 2.
```
This is not a fault of matplotlib! The fault lies on our pytest, which
blindly runs all tests found in the directory tree under the root dir.
(matplotlib test files are supposed to run in a development install,
where the baseline image directory exists, but our install (SPKG) of
matplotlib is not a development install, and hence there's no baseline
image directory.)

So we need to stop pytest from running blind. The failure in the
incremental test workflow results from an error in `sage-runtests`. The
relevant lines are
```python
        exit_code_pytest = 0
        import pytest
        pytest_options = []
        if args.verbose:
            pytest_options.append("-v")
        # #31924: Do not run pytest on individual Python files unless
        # they match the pytest file pattern.  However, pass names
        # of directories. We use 'not os.path.isfile(f)' for this so
that
        # we do not silently hide typos.
        filenames = [f for f in args.filenames
                     if f.endswith("_test.py") or not os.path.isfile(f)]
        if filenames or not args.filenames:   #
<------------------------------------ faulty line!
            print(f"Running pytest on {filenames} with options
{pytest_options}")
            exit_code_pytest = pytest.main(filenames + pytest_options)
            if exit_code_pytest == 5:
                # Exit code 5 means there were no test files, pass in
this case
                exit_code_pytest = 0
```
Look at the faulty line. The condition test allows pytest run without
explicit filenames. This results in running pytest for all test files
found under the (sage) root dir. Hence pytest attempts to run tests in
matplotlib in `local/var/lib/sage/venv-python3.11/lib/python3.11/site-
packages/matplotlib/tests`.

The branch of this PR fixes the problem.

<!-- Why is this change required? What problem does it solve? -->
<!-- If this PR resolves an open issue, please link to it here. For
example "Fixes #12345". -->
<!-- If your change requires a documentation PR, please link it
appropriately. -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
<!-- Feel free to remove irrelevant items. -->

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on
- #12345: short description why this is a dependency
- #34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: #35999
Reported by: Kwankyu Lee
Reviewer(s): Kwankyu Lee, Matthias Köppe, Tobias Diez
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants