From 4c67d198b2f635ae8025bf9a75007ab6fd9e3573 Mon Sep 17 00:00:00 2001 From: Gonzalo Pena-Castellanos Date: Thu, 12 Dec 2019 21:37:55 -0500 Subject: [PATCH] Configure CI with github actions --- .github/workflows/build-linux.yml | 92 +++++++++++++++++++ .github/workflows/build-mac.yml | 69 ++++++++++++++ .github/workflows/build-win.yml | 76 +++++++++++++++ .../azure => .github/workflows}/install.sh | 37 ++++---- conftest.py | 7 ++ continuous_integration/azure/install.bat | 68 -------------- continuous_integration/azure/runtests.bat | 10 -- continuous_integration/azure/runtests.sh | 5 - spyder/app/tests/test_cli_options.py | 1 + spyder/app/tests/test_mainwindow.py | 8 +- .../kite/utils/tests/test_install.py | 5 +- .../plugins/editor/widgets/tests/conftest.py | 9 +- .../editor/widgets/tests/test_codeeditor.py | 4 +- .../plugins/editor/widgets/tests/test_goto.py | 2 +- .../widgets/tests/test_hints_and_calltips.py | 6 +- .../widgets/tests/test_introspection.py | 4 +- .../explorer/widgets/tests/test_explorer.py | 11 +++ .../widgets/tests/test_fileassociations.py | 7 ++ spyder/plugins/ipythonconsole/plugin.py | 14 ++- .../tests/test_ipythonconsole.py | 1 + .../plots/widgets/tests/test_plots_widgets.py | 1 + .../widgets/tests/test_arrayeditor.py | 1 + .../widgets/tests/test_collectioneditor.py | 3 + spyder/utils/tests/test_programs.py | 46 ++++++---- 24 files changed, 333 insertions(+), 154 deletions(-) create mode 100644 .github/workflows/build-linux.yml create mode 100644 .github/workflows/build-mac.yml create mode 100644 .github/workflows/build-win.yml rename {continuous_integration/azure => .github/workflows}/install.sh (53%) delete mode 100644 continuous_integration/azure/install.bat delete mode 100644 continuous_integration/azure/runtests.bat delete mode 100755 continuous_integration/azure/runtests.sh diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml new file mode 100644 index 00000000000..6b2877ed3ab --- /dev/null +++ b/.github/workflows/build-linux.yml @@ -0,0 +1,92 @@ +name: Linux tests + +on: + # This avoids having duplicate builds for a pull request + push: + branches: + - master + - 5.x + - 4.x + pull_request: + branches: + - master + - 5.x + - 4.x + +jobs: + cleanup-previous-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + + build: + name: Py${{ matrix.PYTHON_VERSION }}, ${{ matrix.INSTALL_TYPE }}, ${{ matrix.TEST_TYPE }} + runs-on: ubuntu-latest + env: + CI: 'true' + CODECOV_TOKEN: "56731c25-9b1f-4340-8b58-35739bfbc52d" + OS: 'linux' + PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} + RUN_SLOW: ${{ matrix.TEST_TYPE == 'slow' }} + USE_CONDA: ${{ matrix.INSTALL_TYPE == 'conda' }} + strategy: + fail-fast: false + matrix: + INSTALL_TYPE: ['conda', 'pip'] + PYTHON_VERSION: ['3.7', '2.7'] + TEST_TYPE: ['fast', 'slow'] + exclude: + - INSTALL_TYPE: 'pip' + PYTHON_VERSION: '2.7' + TEST_TYPE: 'fast' + - INSTALL_TYPE: 'pip' + PYTHON_VERSION: '2.7' + TEST_TYPE: 'slow' + steps: + - name: Install dependencies + shell: bash + run: | + sudo apt-get install libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libegl1-mesa libxkbcommon-x11-0 + - name: Checkout branch + uses: actions/checkout@v1.2.0 + - name: Cache pip + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements/*.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install Conda + uses: goanpeca/setup-miniconda@v1 + with: + activate-environment: test + auto-update-conda: true + auto-activate-base: false + python-version: ${{ matrix.PYTHON_VERSION }} + - name: Create test environment + shell: bash -l {0} + run: | + bash -l .github/workflows/install.sh + - name: Show test environment + shell: bash -l {0} + run: | + conda info + conda list + - name: Run tests + shell: bash -l {0} + run: | + xvfb-run --auto-servernum python runtests.py + - name: Run application test + shell: bash -l {0} + run: | + xvfb-run --auto-servernum python bootstrap.py -- --reset + - name: Run manifest checks + shell: bash -l {0} + run: | + check-manifest + - name: Coverage + shell: bash -l {0} + run: | + codecov diff --git a/.github/workflows/build-mac.yml b/.github/workflows/build-mac.yml new file mode 100644 index 00000000000..7e50e939cb4 --- /dev/null +++ b/.github/workflows/build-mac.yml @@ -0,0 +1,69 @@ +name: Mac tests + +on: + # This avoids having duplicate builds for a pull request + push: + branches: + - master + - 5.x + - 4.x + pull_request: + branches: + - master + - 5.x + - 4.x + +jobs: + cleanup-previous-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + + build: + name: Py${{ matrix.PYTHON_VERSION }}, ${{ matrix.INSTALL_TYPE }}, ${{ matrix.TEST_TYPE }} + runs-on: macos-latest + env: + CI: 'true' + CODECOV_TOKEN: "56731c25-9b1f-4340-8b58-35739bfbc52d" + OS: 'macos' + PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} + RUN_SLOW: ${{ matrix.TEST_TYPE == 'slow' }} + USE_CONDA: ${{ matrix.INSTALL_TYPE == 'conda' }} + strategy: + fail-fast: false + matrix: + INSTALL_TYPE: ['conda'] + PYTHON_VERSION: ['3.7', '2.7'] + TEST_TYPE: ['fast', 'slow'] + steps: + - name: Checkout branch + uses: actions/checkout@v1.2.0 + - name: Install Conda + uses: goanpeca/setup-miniconda@v1 + with: + activate-environment: test + auto-update-conda: true + python-version: ${{ matrix.PYTHON_VERSION }} + - name: Create test environment + shell: bash -l {0} + run: | + bash -l .github/workflows/install.sh + - name: Show test environment + shell: bash -l {0} + run: | + conda info + conda list + - name: Run tests + shell: bash -l {0} + run: | + python runtests.py + - name: Run application test + shell: bash -l {0} + run: | + python bootstrap.py -- --reset + - name: Coverage + shell: bash -l {0} + run: | + codecov diff --git a/.github/workflows/build-win.yml b/.github/workflows/build-win.yml new file mode 100644 index 00000000000..7385a55078a --- /dev/null +++ b/.github/workflows/build-win.yml @@ -0,0 +1,76 @@ +name: Win tests + +on: + # This avoids having duplicate builds for a pull request + push: + branches: + - master + - 5.x + - 4.x + pull_request: + branches: + - master + - 5.x + - 4.x + +jobs: + cleanup-previous-runs: + runs-on: ubuntu-latest + steps: + - uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + + build: + name: Py${{ matrix.PYTHON_VERSION }}, ${{ matrix.INSTALL_TYPE }}, ${{ matrix.TEST_TYPE }} + runs-on: windows-latest + env: + CI: 'true' + CODECOV_TOKEN: "56731c25-9b1f-4340-8b58-35739bfbc52d" + OS: 'win' + PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} + RUN_SLOW: ${{ matrix.TEST_TYPE == 'slow' }} + USE_CONDA: ${{ matrix.INSTALL_TYPE == 'conda' }} + strategy: + fail-fast: false + matrix: + INSTALL_TYPE: ['conda'] + PYTHON_VERSION: ['3.7', '2.7'] + TEST_TYPE: ['fast', 'slow'] + steps: + - name: Checkout branch + uses: actions/checkout@v1.2.0 + - name: Cache pip + uses: actions/cache@v1 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-pip-${{ hashFiles('requirements/*.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install Conda + uses: goanpeca/setup-miniconda@v1 + with: + activate-environment: test + auto-update-conda: true + python-version: ${{ matrix.PYTHON_VERSION }} + - name: Create test environment + shell: bash -l {0} + run: | + bash -l .github/workflows/install.sh + - name: Show test environment + shell: bash -l {0} + run: | + conda info + conda list + - name: Run tests + shell: bash -l {0} + run: | + python runtests.py + - name: Run application test + shell: bash -l {0} + run: | + python bootstrap.py -- --reset + - name: Coverage + shell: bash -l {0} + run: | + codecov diff --git a/continuous_integration/azure/install.sh b/.github/workflows/install.sh similarity index 53% rename from continuous_integration/azure/install.sh rename to .github/workflows/install.sh index cda842253b5..ffa9523255e 100755 --- a/continuous_integration/azure/install.sh +++ b/.github/workflows/install.sh @@ -1,33 +1,25 @@ #!/bin/bash -ex -# -- Installl dependencies -if [ "$USE_CONDA" = "yes" ]; then - # Avoid problems with invalid SSL certificates - if [ "$PYTHON_VERSION" = "2.7" ]; then - conda install -q -y python=2.7.16=h97142e2_0 - fi +# Install dependencies +if [ "$USE_CONDA" = "true" ]; then - # Install nomkl to avoid installing Intel MKL libraries - conda install -q -y nomkl + if [ "$OS" != "win" ]; then + # Install nomkl to avoid installing Intel MKL libraries + conda install nomkl -q -y + fi # Install main dependencies - conda install -q -y -c spyder-ide --file requirements/conda.txt + conda install python=$PYTHON_VERSION --file requirements/conda.txt -q -y # Install test ones - conda install -q -y -c spyder-ide --file requirements/tests.txt - - # Github backend tests are failing with 1.1.1d - conda install -q -y openssl=1.1.1c + conda install python=$PYTHON_VERSION --file requirements/tests.txt -c spyder-ide -q -y # Remove spyder-kernels to be sure that we use its subrepo - conda remove -q -y --force spyder-kernels + conda remove spyder-kernels --force -q -y # Install python-language-server from Github with no deps - pip install -q --no-deps git+https://github.com/palantir/python-language-server + pip install --no-deps git+https://github.com/palantir/python-language-server -q else - # Github backend tests are failing with 1.1.1d - conda install -q -y openssl=1.1.1c - # Update pip and setuptools pip install -U pip setuptools @@ -44,19 +36,22 @@ else pip install git+https://github.com/jupyter/qtconsole.git # Remove spyder-kernels to be sure that we use its subrepo - pip uinstall -q -y spyder-kernels + pip uninstall spyder-kernels -q -y # Install python-language-server from Github - pip install -q git+https://github.com/palantir/python-language-server + pip install git+https://github.com/palantir/python-language-server -q fi # To check our manifest pip install check-manifest -# Create environment for Jedi environments testsTest for Jedi environments +# Create environment for Jedi environments tests conda create -n jedi-test-env -q -y python=3.6 flask spyder-kernels conda list -n jedi-test-env # Create environment to test conda activation before launching a spyder kernel conda create -n spytest-ž -q -y python=3.6 spyder-kernels conda list -n spytest-ž + +# Coverage +conda install -n test codecov diff --git a/conftest.py b/conftest.py index c2c66bff435..47d59419f7b 100644 --- a/conftest.py +++ b/conftest.py @@ -15,6 +15,13 @@ import os.path as osp import shutil import sys +import warnings + + +if sys.version_info[0] == 2: + # Hide warnings on py2 due to qtawesome as it makes the results unreadable + warnings.filterwarnings("ignore") + # To activate/deactivate certain things for pytest's only # NOTE: Please leave this before any other import here!! diff --git a/continuous_integration/azure/install.bat b/continuous_integration/azure/install.bat deleted file mode 100644 index 756c3592f83..00000000000 --- a/continuous_integration/azure/install.bat +++ /dev/null @@ -1,68 +0,0 @@ -:: Install dependencies -if %USE_CONDA% == yes ( - :: The newly introduced changes to the Python packages in Anaconda - :: are breaking our tests. Reverting to known working builds. - if %PYTHON_VERSION% == 3.6 ( - conda install -q -y python=3.6.8=h9f7ef89_7 - ) - - conda install -q -y -c spyder-ide --file requirements/conda.txt - if errorlevel 1 exit 1 - - conda install -q -y -c spyder-ide --file requirements/tests.txt - if errorlevel 1 exit 1 - - :: Github backend tests are failing with 1.1.1d - conda install -q -y openssl=1.1.1c - if errorlevel 1 exit 1 - - :: Remove spyder-kernels to be sure that we use its subrepo - conda remove -q -y --force spyder-kernels - if errorlevel 1 exit 1 -) else ( - :: Github backend tests are failing with 1.1.1d - conda install -q -y openssl=1.1.1c - if errorlevel 1 exit 1 - - :: Install Spyder and its dependencies from our setup.py - pip install -e .[test] - if errorlevel 1 exit 1 - - :: Install qtpy from Github - pip install git+https://github.com/spyder-ide/qtpy.git - if errorlevel 1 exit 1 - - :: Install qtconsole from Github - pip install git+https://github.com/jupyter/qtconsole.git - if errorlevel 1 exit 1 - - :: Remove spyder-kernels to be sure that we use its subrepo - pip uninstall -q -y spyder-kernels - if errorlevel 1 exit 1 -) - -:: To check our manifest -pip install check-manifest -if errorlevel 1 exit 1 - -:: Create environment for Jedi environments tests -conda create -n jedi-test-env -q -y python=3.6 flask spyder-kernels -if errorlevel 1 exit 1 - -conda list -n jedi-test-env -if errorlevel 1 exit 1 - -:: Create environment to test conda activation before launching a spyder kernel -conda create -n spytest-ž -q -y python=3.6 spyder-kernels -if errorlevel 1 exit 1 - -conda list -n spytest-ž -if errorlevel 1 exit 1 - -:: Install python-language-server from master -pip install -q --no-deps git+https://github.com/palantir/python-language-server -if errorlevel 1 exit 1 - -:: Install codecov -pip install -q codecov -if errorlevel 1 exit 1 diff --git a/continuous_integration/azure/runtests.bat b/continuous_integration/azure/runtests.bat deleted file mode 100644 index 535096c1280..00000000000 --- a/continuous_integration/azure/runtests.bat +++ /dev/null @@ -1,10 +0,0 @@ - -:: Python 2 tests are passing correctly but erroring probably because of PyQt 5.6 -if %PYTHON_VERSION% == 2.7 ( - python runtests.py || exit 0 -) else ( - python runtests.py || python runtests.py || python runtests.py || python runtests.py || python runtests.py || exit 1 -) - -:: Run codecov if things were successful -codecov diff --git a/continuous_integration/azure/runtests.sh b/continuous_integration/azure/runtests.sh deleted file mode 100755 index 9648ad090f4..00000000000 --- a/continuous_integration/azure/runtests.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -ex - -# Run tests -python bootstrap.py -- --reset -python runtests.py diff --git a/spyder/app/tests/test_cli_options.py b/spyder/app/tests/test_cli_options.py index 2a8a6af8af5..cae1c8eb0b2 100644 --- a/spyder/app/tests/test_cli_options.py +++ b/spyder/app/tests/test_cli_options.py @@ -11,6 +11,7 @@ from spyder.app import cli_options +@pytest.mark.first def test_get_options(): getopt = cli_options.get_options diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py index b8436ff0a59..0e1f1497c72 100644 --- a/spyder/app/tests/test_mainwindow.py +++ b/spyder/app/tests/test_mainwindow.py @@ -237,9 +237,10 @@ def remove_test_dir(): # ============================================================================= @flaky(max_runs=3) @pytest.mark.slow +@pytest.mark.first @pytest.mark.single_instance @pytest.mark.skipif((os.environ.get('CI', None) is None or (PY2 - and sys.platform == 'darwin')), + and not sys.platform.startswith('linux'))), reason="It's not meant to be run outside of CIs") def test_single_instance_and_edit_magic(main_window, qtbot, tmpdir): """Test single instance mode and %edit magic.""" @@ -690,8 +691,7 @@ def test_move_to_first_breakpoint(main_window, qtbot, debugcell): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif(os.environ.get('CI', None) is None or sys.platform == 'darwin', - reason="It's not meant to be run locally and fails in macOS") +@pytest.mark.skipif(os.name == 'nt', reason='Fails on windows!') def test_runconfig_workdir(main_window, qtbot, tmpdir): """Test runconfig workdir options.""" CONF.set('run', 'configurations', []) @@ -746,7 +746,7 @@ def test_runconfig_workdir(main_window, qtbot, tmpdir): @pytest.mark.slow @flaky(max_runs=3) -@pytest.mark.skipif((os.name == 'nt' and PY2) or sys.platform == 'darwin', +@pytest.mark.skipif(os.name == 'nt' or sys.platform == 'darwin', reason="It's failing there") def test_dedicated_consoles(main_window, qtbot): """Test running code in dedicated consoles.""" diff --git a/spyder/plugins/completion/kite/utils/tests/test_install.py b/spyder/plugins/completion/kite/utils/tests/test_install.py index 87d5228d6ad..e8084da7c4b 100644 --- a/spyder/plugins/completion/kite/utils/tests/test_install.py +++ b/spyder/plugins/completion/kite/utils/tests/test_install.py @@ -28,10 +28,7 @@ @pytest.mark.slow @pytest.mark.first -@pytest.mark.skipif((not sys.platform.startswith('linux') - or os.environ.get('CI', None) is None), - reason=("Only works reliably on Linux and " - "it's not meant to be run outside of CIs")) +@pytest.mark.skipif(bool(os.environ.get('CI', None)), reason='Fails on CI!') def test_kite_install(qtbot): """Test the correct execution of the installation process of kite.""" install_manager = KiteInstallationThread(None) diff --git a/spyder/plugins/editor/widgets/tests/conftest.py b/spyder/plugins/editor/widgets/tests/conftest.py index b5763dc17a7..1fbdd126983 100644 --- a/spyder/plugins/editor/widgets/tests/conftest.py +++ b/spyder/plugins/editor/widgets/tests/conftest.py @@ -146,14 +146,7 @@ def teardown(): return editor, kite -# Windows tests fail if using module scope -if os.name == 'nt': - LSP_PLUGIN_SCOPE = 'module' -else: - LSP_PLUGIN_SCOPE = 'function' - - -@pytest.fixture(scope=LSP_PLUGIN_SCOPE) +@pytest.fixture(scope='function') def lsp_plugin(qtbot_module, request): # Activate pycodestyle and pydocstyle CONF.set('lsp-server', 'pycodestyle', True) diff --git a/spyder/plugins/editor/widgets/tests/test_codeeditor.py b/spyder/plugins/editor/widgets/tests/test_codeeditor.py index a89e031f65e..a788afd1537 100644 --- a/spyder/plugins/editor/widgets/tests/test_codeeditor.py +++ b/spyder/plugins/editor/widgets/tests/test_codeeditor.py @@ -243,9 +243,9 @@ def test_comment(editorbot): cursor.setPosition(8) cursor.setPosition(11, QTextCursor.KeepAnchor) widget.setTextCursor(cursor) - qtbot.keyPress(widget, "1", modifier=Qt.ControlModifier) + widget.toggle_comment() assert widget.toPlainText() == "# import numpy" - qtbot.keyPress(widget, "1", modifier=Qt.ControlModifier) + widget.toggle_comment() assert widget.toPlainText() == "import numpy" diff --git a/spyder/plugins/editor/widgets/tests/test_goto.py b/spyder/plugins/editor/widgets/tests/test_goto.py index b914bc64732..5ae7f6542d7 100644 --- a/spyder/plugins/editor/widgets/tests/test_goto.py +++ b/spyder/plugins/editor/widgets/tests/test_goto.py @@ -29,7 +29,7 @@ TEST_FILE_REL = 'conftest.py' -@pytest.mark.skipif(os.name == 'nt', reason="It fails on Windows") +@pytest.mark.skipif(bool(os.environ.get('CI', None)), reason='Fails on CI!') @pytest.mark.parametrize('params', [ # Parameter, expected output 1, full file path, expected output 2 # ---------------------------------------------------------------- diff --git a/spyder/plugins/editor/widgets/tests/test_hints_and_calltips.py b/spyder/plugins/editor/widgets/tests/test_hints_and_calltips.py index f2781e125d9..86547af9c60 100644 --- a/spyder/plugins/editor/widgets/tests/test_hints_and_calltips.py +++ b/spyder/plugins/editor/widgets/tests/test_hints_and_calltips.py @@ -126,8 +126,7 @@ def test_get_calltips(qtbot, lsp_codeeditor, params): @pytest.mark.slow @pytest.mark.second -@pytest.mark.skipif(sys.platform != 'darwin' and bool(os.environ.get('CI')), - reason="Fails on Windows and Linux on CI") +@pytest.mark.skipif(sys.platform == 'darwin', reason='Fails on Mac') @pytest.mark.parametrize('params', [ # Parameter, Expected Output ('"".format', '-> str'), @@ -169,8 +168,7 @@ def test_get_hints(qtbot, lsp_codeeditor, params, capsys): @pytest.mark.slow @pytest.mark.second -@pytest.mark.skipif(sys.platform != 'darwin', - reason="Fails on Windows and Linux") +@pytest.mark.skipif(sys.platform == 'darwin', reason='Fails on Mac') def test_get_hints_not_triggered(qtbot, lsp_codeeditor): """Test that the editor is not returning hover hints for empty docs.""" code_editor, _ = lsp_codeeditor diff --git a/spyder/plugins/editor/widgets/tests/test_introspection.py b/spyder/plugins/editor/widgets/tests/test_introspection.py index 21e9a3e9f3d..d8a30565462 100644 --- a/spyder/plugins/editor/widgets/tests/test_introspection.py +++ b/spyder/plugins/editor/widgets/tests/test_introspection.py @@ -93,9 +93,7 @@ def test_space_completion(lsp_codeeditor, qtbot): @pytest.mark.slow @pytest.mark.first @flaky(max_runs=5) -@pytest.mark.skipif( - os.environ.get('CI') and (PY2 or os.name != 'nt'), - reason='Fails consistently on CI with Linux/Mac or Python 2') +@pytest.mark.skipif(bool(os.environ.get('CI', None)), reason='Fails on CI!') def test_hide_widget_completion(lsp_codeeditor, qtbot): """Validate hiding completion widget after a delimeter or operator.""" code_editor, _ = lsp_codeeditor diff --git a/spyder/plugins/explorer/widgets/tests/test_explorer.py b/spyder/plugins/explorer/widgets/tests/test_explorer.py index 8a4158c28b0..68b81a95e87 100644 --- a/spyder/plugins/explorer/widgets/tests/test_explorer.py +++ b/spyder/plugins/explorer/widgets/tests/test_explorer.py @@ -24,6 +24,7 @@ ProjectExplorerTest) from spyder.plugins.projects.widgets.explorer import ( ProjectExplorerTest as ProjectExplorerTest2) +from spyder.py3compat import PY2 @pytest.fixture @@ -227,6 +228,7 @@ def run_test_helper(single_click, initial_index): run_test_helper(single_click=False, initial_index=initial_index) +@pytest.mark.first def test_get_common_file_associations(qtbot, file_explorer_associations): widget = file_explorer_associations.explorer.treewidget associations = widget.get_common_file_associations( @@ -244,6 +246,7 @@ def test_get_common_file_associations(qtbot, file_explorer_associations): assert associations[0][-1] == '/some/fake/some_app_1' + ext +@pytest.mark.first def test_get_file_associations(qtbot, file_explorer_associations): widget = file_explorer_associations.explorer.treewidget associations = widget.get_file_associations('/some/path/file.txt') @@ -256,6 +259,8 @@ def test_get_file_associations(qtbot, file_explorer_associations): assert associations[0][-1] == '/some/fake/some_app_1' + ext +@pytest.mark.first +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on win and py2!') def test_create_file_manage_actions(qtbot, file_explorer_associations, tmp_path): widget = widget = file_explorer_associations.explorer.treewidget @@ -285,6 +290,8 @@ def test_create_file_manage_actions(qtbot, file_explorer_associations, assert not action_texts +@pytest.mark.first +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on win and py2!') def test_clicked(qtbot, file_explorer_associations, tmp_path): widget = file_explorer_associations.explorer.treewidget some_dir = tmp_path / 'some_dir' @@ -317,6 +324,8 @@ def interact_2(): qtbot.keyClick(widget, Qt.Key_Return) +@pytest.mark.first +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on win and py2!') def test_check_launch_error_codes(qtbot, file_explorer_associations): widget = file_explorer_associations.explorer.treewidget @@ -347,6 +356,8 @@ def interact_2(): assert not res +@pytest.mark.first +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on win and py2!') def test_open_association(qtbot, file_explorer_associations, tmp_path): widget = file_explorer_associations.explorer.treewidget some_dir = tmp_path / 'some_dir' diff --git a/spyder/plugins/explorer/widgets/tests/test_fileassociations.py b/spyder/plugins/explorer/widgets/tests/test_fileassociations.py index 08fe2081cd7..b286c17837f 100644 --- a/spyder/plugins/explorer/widgets/tests/test_fileassociations.py +++ b/spyder/plugins/explorer/widgets/tests/test_fileassociations.py @@ -21,8 +21,11 @@ # Local imports from spyder.plugins.explorer.widgets.fileassociations import ( ApplicationsDialog, FileAssociationsWidget, InputTextDialog) +from spyder.py3compat import PY2 +@pytest.mark.first +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on win and py2!') def test_input_text_dialog(qtbot): widget = InputTextDialog() qtbot.addWidget(widget) @@ -53,6 +56,8 @@ def test_input_text_dialog(qtbot): widget.validate() +@pytest.mark.first +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on win and py2!') def test_apps_dialog(qtbot, tmp_path): widget = ApplicationsDialog() qtbot.addWidget(widget) @@ -140,6 +145,8 @@ def create_timer(func, interval=500): return timer +@pytest.mark.first +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on win and py2!') def test_file_assoc_widget(file_assoc_widget): qtbot, widget = file_assoc_widget diff --git a/spyder/plugins/ipythonconsole/plugin.py b/spyder/plugins/ipythonconsole/plugin.py index fa1d94a3a7a..7a69f0f6a49 100644 --- a/spyder/plugins/ipythonconsole/plugin.py +++ b/spyder/plugins/ipythonconsole/plugin.py @@ -45,7 +45,7 @@ from spyder.plugins.ipythonconsole.utils.style import create_qss_style from spyder.plugins.ipythonconsole.widgets import (ClientWidget, KernelConnectionDialog) -from spyder.py3compat import is_string, to_text_string, PY38_OR_MORE +from spyder.py3compat import is_string, to_text_string, PY2, PY38_OR_MORE from spyder.utils import encoding from spyder.utils import icon_manager as ima from spyder.utils import programs, sourcecode @@ -844,10 +844,16 @@ def interpreter_versions(self): import subprocess versions = {} pyexec = CONF.get('main_interpreter', 'executable') - py_cmd = '%s -c "import sys; print(sys.version)"' % pyexec - ipy_cmd = ('%s -c "import IPython.core.release as r; print(r.version)"' - % pyexec) + py_cmd = u'%s -c "import sys; print(sys.version)"' % pyexec + ipy_cmd = ( + u'%s -c "import IPython.core.release as r; print(r.version)"' + % pyexec + ) for cmd in [py_cmd, ipy_cmd]: + # Testing + if PY2: + cmd = cmd.encode('utf-8') + try: proc = programs.run_shell_command(cmd) output, _err = proc.communicate() diff --git a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py index 76c1c496166..65a2a691ccf 100644 --- a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py +++ b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py @@ -1580,6 +1580,7 @@ def test_calltip(ipyconsole, qtbot): @flaky(max_runs=3) +@pytest.mark.first @pytest.mark.test_environment_interpreter def test_conda_env_activation(ipyconsole, qtbot): """ diff --git a/spyder/plugins/plots/widgets/tests/test_plots_widgets.py b/spyder/plugins/plots/widgets/tests/test_plots_widgets.py index 70fb71efc28..49ed399668f 100644 --- a/spyder/plugins/plots/widgets/tests/test_plots_widgets.py +++ b/spyder/plugins/plots/widgets/tests/test_plots_widgets.py @@ -98,6 +98,7 @@ def png_to_qimage(png): # ============================================================================= # ---- Tests # ============================================================================= +@pytest.mark.first @pytest.mark.parametrize("fmt, fext", [('image/png', '.png'), ('image/svg+xml', '.svg')]) def test_handle_new_figures(figbrowser, tmpdir, fmt, fext): diff --git a/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py b/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py index 2399e60541e..922b92b979d 100644 --- a/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py +++ b/spyder/plugins/variableexplorer/widgets/tests/test_arrayeditor.py @@ -239,6 +239,7 @@ def test_arrayeditor_edit_2d_array(qtbot): assert np.sum(diff_arr != dlg.get_value()) == 2 +@pytest.mark.slow def test_arrayeditor_edit_complex_array(qtbot): """See: spyder-ide/spyder#7848""" cnum = -1+0.5j diff --git a/spyder/plugins/variableexplorer/widgets/tests/test_collectioneditor.py b/spyder/plugins/variableexplorer/widgets/tests/test_collectioneditor.py index 998c5af3eec..13c08619b10 100644 --- a/spyder/plugins/variableexplorer/widgets/tests/test_collectioneditor.py +++ b/spyder/plugins/variableexplorer/widgets/tests/test_collectioneditor.py @@ -37,6 +37,8 @@ NamespacesBrowserFinder) from spyder.plugins.variableexplorer.widgets.tests.test_dataframeeditor import \ generate_pandas_indexes +from spyder.py3compat import PY2 + # ============================================================================= # Constants @@ -311,6 +313,7 @@ def test_shows_dataframeeditor_when_editing_index(qtbot, monkeypatch): mockDataFrameEditor_instance.show.assert_called_once_with() +@pytest.mark.skipif(os.name == 'nt' and PY2, reason='Fails on Win and py2') def test_sort_collectionsmodel(): var_list1 = [0, 1, 2] var_list2 = [3, 4, 5, 6] diff --git a/spyder/utils/tests/test_programs.py b/spyder/utils/tests/test_programs.py index d480d3e6c49..46d42166dee 100644 --- a/spyder/utils/tests/test_programs.py +++ b/spyder/utils/tests/test_programs.py @@ -24,19 +24,19 @@ run_python_script_in_terminal, shell_split) if os.name == 'nt': - python_dir = os.environ['PYTHON'] if os.environ.get('CI', None) else '' + python_dir = 'C:\\Miniconda\\' VALID_INTERPRETER = os.path.join(python_dir, 'python.exe') VALID_W_INTERPRETER = os.path.join(python_dir, 'pythonw.exe') INVALID_INTERPRETER = os.path.join(python_dir, 'Scripts', 'ipython.exe') else: if sys.platform.startswith('linux'): - home_dir = os.environ['HOME'] + home_dir = '/usr/share/miniconda/' else: - # Parent Miniconda dir in macOS Azure VMs - home_dir = os.path.join('/usr', 'local') - VALID_INTERPRETER = os.path.join(home_dir, 'miniconda', 'bin', 'python') - VALID_W_INTERPRETER = os.path.join(home_dir, 'miniconda', 'bin', 'pythonw') - INVALID_INTERPRETER = os.path.join(home_dir, 'miniconda', 'bin', 'ipython') + home_dir = '/usr/local/miniconda/' + + VALID_INTERPRETER = os.path.join(home_dir, 'bin', 'python') + VALID_W_INTERPRETER = os.path.join(home_dir, 'bin', 'pythonw') + INVALID_INTERPRETER = os.path.join(home_dir, 'bin', 'ipython') # ============================================================================= @@ -78,9 +78,7 @@ def test_is_valid_w_interpreter(): @flaky(max_runs=3) -@pytest.mark.skipif( - os.environ.get('CI', None) is None, - reason='fails sometimes locally') +@pytest.mark.skipif(bool(os.environ.get('CI', None)), reason='Only on CI!') def test_run_python_script_in_terminal(scriptpath, qtbot): """ Test running a Python script in an external terminal when specifying @@ -98,9 +96,11 @@ def test_run_python_script_in_terminal(scriptpath, qtbot): @flaky(max_runs=3) +@pytest.mark.first @pytest.mark.skipif( - os.environ.get('CI', None) is None, - reason='fails sometimes locally') + os.environ.get('CI', None) is None or os.name == 'nt', + reason='Only on CI and not on windows!', +) def test_run_python_script_in_terminal_blank_wdir(scriptpath_with_blanks, qtbot): """ @@ -120,9 +120,11 @@ def test_run_python_script_in_terminal_blank_wdir(scriptpath_with_blanks, @flaky(max_runs=3) +@pytest.mark.first @pytest.mark.skipif( - os.environ.get('CI', None) is None, - reason='fails sometimes locally') + os.environ.get('CI', None) is None or os.name == 'nt', + reason='Only on CI and not on windows!', +) def test_run_python_script_in_terminal_with_wdir_empty(scriptpath, qtbot): """ Test running a Python script in an external terminal without specifying @@ -142,38 +144,44 @@ def test_run_python_script_in_terminal_with_wdir_empty(scriptpath, qtbot): assert res == 'done' -@pytest.mark.skipif(os.environ.get('CI', None) is None, - reason='It only runs in CI services.') +@pytest.mark.first +@pytest.mark.skipif(os.environ.get('CI', None) is None, reason='Only on CI!') def test_is_valid_interpreter(): assert is_python_interpreter(VALID_INTERPRETER) -@pytest.mark.skipif(os.environ.get('CI', None) is None, - reason='It only runs in CI services.') +@pytest.mark.first +@pytest.mark.skipif(os.environ.get('CI', None) is None, reason='Only on CI!') def test_is_invalid_interpreter(): assert not is_python_interpreter(INVALID_INTERPRETER) +@pytest.mark.first +@pytest.mark.skipif(os.environ.get('CI', None) is None, reason='Only on CI!') def test_is_valid_interpreter_name(): names = ['python', 'pythonw', 'python2.7', 'python3.5', 'python.exe', 'pythonw.exe'] assert all([is_python_interpreter_valid_name(n) for n in names]) + def test_find_program(): """Test if can find the program.""" assert find_program('git') + def test_shell_split(): """Test if the text can be split using shell-like sintax.""" assert shell_split('-q -o -a') == ['-q', '-o', '-a'] assert shell_split('-q "d:\\Python de xxxx\\t.txt" -o -a') == \ ['-q', 'd:\\Python de xxxx\\t.txt', '-o', '-a'] + def test_check_version(): """Test the compare function for versions.""" assert check_version('0.9.4-1', '0.9.4', '>=') assert check_version('3.0.0rc1', '3.0.0', '<') assert check_version('1.0', '1.0b2', '>') + def test_is_module_installed(): """Test if a module with the proper version is installed""" assert is_module_installed('qtconsole', '>=4.5') @@ -181,8 +189,6 @@ def test_is_module_installed(): assert is_module_installed('jedi', '>=0.7.0') -@pytest.mark.skipif(os.name == 'nt' and os.environ.get('AZURE') is not None, - reason="Fails on Windows/Azure") def test_is_module_installed_with_custom_interpreter(): """Test if a module with the proper version is installed""" current = sys.executable