diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 313a266..c5ad05e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-20.04, macos-11, windows-2019 ] - python-version: [ 3.7, 3.9, 3.8, "3.10", "3.11" ] + python-version: [ 3.7, 3.9, 3.8, "3.10", "3.11", "3.12" ] env: PYTHON_VERSION: ${{ matrix.python-version }} @@ -43,13 +43,15 @@ jobs: - name: Install run: | if [[ "$PYTHON_VERSION" == "3.7" ]] || [[ "$PYTHON_VERSION" == "3.8" ]]; then - conda install scipy=1.3 numpy=1.16 nose + conda install scipy=1.3 numpy=1.16 pytest elif [[ "$PYTHON_VERSION" == "3.9" ]]; then - conda install scipy=1.5 numpy=1.19 nose + conda install scipy=1.5 numpy=1.19 pytest elif [[ "$PYTHON_VERSION" == "3.10" ]]; then - conda install scipy=1.7 numpy=1.21 nose + conda install scipy=1.7 numpy=1.21 pytest elif [[ "$PYTHON_VERSION" == "3.11" ]]; then - conda install scipy=1.9.3 numpy=1.23.4 nose + conda install scipy=1.9.3 numpy=1.23.4 pytest + elif [[ "$PYTHON_VERSION" == "3.12" ]]; then + conda install scipy=1.11.3 numpy=1.26.0 pytest fi if [[ "$RUNNER_OS" == "macOS" ]]; then sudo rm -rf /Library/Developer/CommandLineTools @@ -58,7 +60,7 @@ jobs: - name: Test run: | make install - python -m nose + python -m pytest rm -rf build/ build_wheels: @@ -69,7 +71,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-20.04, macos-11, windows-2019 ] - python-version: [ 3.7, 3.9, "3.10", "3.11" ] + python-version: [ 3.7, 3.9, "3.10", "3.11", "3.12" ] include: - os: ubuntu-20.04 python-version: 3.8 @@ -107,7 +109,7 @@ jobs: env: CIBW_BUILD: "cp3${{env.PYTHON_SUBVERSION}}-*" CIBW_SKIP: "*-win32 *-manylinux_i686 *-musllinux*" - uses: joerick/cibuildwheel@v2.11.2 + uses: joerick/cibuildwheel@v2.16.5 - name: Build source if: ${{env.DEPLOY == 'True' && env.SINGLE_ACTION_CONFIG == 'True'}} diff --git a/Pipfile b/Pipfile index 6854c29..bca92ed 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [dev-packages] -nose = "*" +pytest = "*" [packages] numpy = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 2904dfa..e39d698 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c3af636b572b51c57671422722e7280a3a003233795df97e0a2dee180f12e04f" + "sha256": "01e35b99ecbe27e2ed9f2ab1d12dbee14db6e5ebafba221a324d420eefbe6f1a" }, "pipfile-spec": 6, "requires": { @@ -18,43 +18,81 @@ "default": { "numpy": { "hashes": [ - "sha256:0739146eaf4985962f07c62f7133aca89f3a600faac891ce6c7f3a1e2afe5272", - "sha256:07e21f14490324cc1160db101e9b6c1233c33985af4cb1d301dd02650fea1d7f", - "sha256:0f6a5ed0cd7ab1da11f5c07a8ecada73fc55a70ef7bb6311a4109891341d7277", - "sha256:0fd65cbbfdbf76bbf80c445d923b3accefea0fe2c2082049e0ce947c81fe1d3f", - "sha256:20cac3123d791e4bf8482a580d98d6b5969ba348b9d5364df791ba3a666b660d", - "sha256:528ce59ded2008f9e8543e0146acb3a98a9890da00adf8904b1e18c82099418b", - "sha256:56e392b7c738bd70e6f46cf48c8194d3d1dd4c5a59fae4b30c58bb6ef86e5233", - "sha256:675e0f23967ce71067d12b6944add505d5f0a251f819cfb44bdf8ee7072c090d", - "sha256:6be6b0ca705321c178c9858e5ad5611af664bbdfae1df1541f938a840a103888", - "sha256:719d914f564f35cce4dc103808f8297c807c9f0297ac183ed81ae8b5650e698e", - "sha256:768e777cc1ffdbf97c507f65975c8686ebafe0f3dc8925d02ac117acc4669ce9", - "sha256:7f76d406c6b998d6410198dcb82688dcdaec7d846aa87e263ccf52efdcfeba30", - "sha256:8c18ee4dddd5c6a811930c0a7c7947bf16387da3b394725f6063f1366311187d", - "sha256:99051e03b445117b26028623f1a487112ddf61a09a27e2d25e6bc07d37d94f25", - "sha256:a1413d06abfa942ca0553bf3bccaff5fdb36d55b84f2248e36228db871147dab", - "sha256:a7157c9ac6bddd2908c35ef099e4b643bc0e0ebb4d653deb54891d29258dd329", - "sha256:a958bf9d4834c72dee4f91a0476e7837b8a2966dc6fcfc42c421405f98d0da51", - "sha256:bb370120de6d26004358611441e07acda26840e41dfedc259d7f8cc613f96495", - "sha256:d0928076d9bd8a98de44e79b1abe50c1456e7abbb40af7ef58092086f1a6c729", - "sha256:d858423f5ed444d494b15c4cc90a206e1b8c31354c781ac7584da0d21c09c1c3", - "sha256:e6120d63b50e2248219f53302af7ec6fa2a42ed1f37e9cda2c76dbaca65036a7", - "sha256:f2b1378b63bdb581d5d7af2ec0373c8d40d651941d283a2afd7fc71184b3f570", - "sha256:facc6f925c3099ac01a1f03758100772560a0b020fb9d70f210404be08006bcb" + "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd", + "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b", + "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e", + "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f", + "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f", + "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178", + "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3", + "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4", + "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e", + "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0", + "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00", + "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419", + "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4", + "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6", + "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166", + "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b", + "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3", + "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf", + "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2", + "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2", + "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36", + "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03", + "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce", + "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6", + "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13", + "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5", + "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e", + "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485", + "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137", + "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374", + "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58", + "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b", + "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb", + "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b", + "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda", + "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511" ], "index": "pypi", - "version": "==1.14.2" + "markers": "python_version >= '3.9'", + "version": "==1.26.3" } }, "develop": { - "nose": { + "iniconfig": { "hashes": [ - "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", - "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", - "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98" + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "packaging": { + "hashes": [ + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2" + }, + "pluggy": { + "hashes": [ + "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", + "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + ], + "markers": "python_version >= '3.8'", + "version": "==1.4.0" + }, + "pytest": { + "hashes": [ + "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c", + "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6" ], "index": "pypi", - "version": "==1.3.7" + "markers": "python_version >= '3.8'", + "version": "==8.0.0" } } } diff --git a/setup.py b/setup.py index 1cbdf6c..855b660 100644 --- a/setup.py +++ b/setup.py @@ -81,6 +81,5 @@ def finalize_options(self): "numpy >= 1.6", "scipy >= 0.9" ], - test_suite='nose.collector', - tests_require=['nose'] + tests_require=['pytest'] ) diff --git a/src/test_interface.py b/src/test_interface.py index aa18622..3f4a138 100644 --- a/src/test_interface.py +++ b/src/test_interface.py @@ -1,35 +1,8 @@ -# for python 3 testing compatibility -from __future__ import print_function import platform - -def import_error(msg): - print() - print("## IMPORT ERROR:", msg) - print() - -try: - from nose.tools import assert_raises, assert_almost_equals -except ImportError: - import_error("Please install nose to run tests.") - raise - -try: - import ecos -except ImportError: - import_error("You must install the ecos module before running tests.") - raise - -try: - import numpy as np -except ImportError: - import_error("Please install numpy.") - raise - -try: - import scipy.sparse as sp -except ImportError: - import_error("Please install scipy.") - raise +import pytest +import ecos +import numpy as np +import scipy.sparse as sp # global data structures for problem c = np.array([-1.]) @@ -39,51 +12,45 @@ def import_error(msg): b = np.array([3.]) dims = {'q': [], 'l': 2} -def check_solution(solution, expected): - assert_almost_equals(solution, expected, places=5) - -def test_problems(): - myopts = {'feastol': 2e-8, 'reltol': 2e-8, 'abstol': 2e-8, 'verbose':True}; - sol = ecos.solve(c, G, h, dims, **myopts) - yield check_solution, sol['x'][0], 4 - - sol = ecos.solve(c, G, h, dims, A, b, **myopts) - yield check_solution, sol['x'][0], 3 - new_dims = {'q':[2], 'l': 0} - sol = ecos.solve(c, G, h, new_dims, **myopts) - yield check_solution, sol['x'][0], 2 - -if platform.python_version_tuple() < ('3','0','0'): - def test_problems_with_longs(): - new_dims = {'q': [], 'l': long(2)} - myopts = {'feastol': 2e-8, 'reltol': 2e-8, 'abstol': 2e-8}; - sol = ecos.solve(c, G, h, new_dims, **myopts) - yield check_solution, sol['x'][0], 4 - - sol = ecos.solve(c, G, h, new_dims, A, b, **myopts) - yield check_solution, sol['x'][0], 3 - - new_dims = {'q':[long(2)], 'l': 0} - sol = ecos.solve(c, G, h, new_dims, **myopts) - yield check_solution, sol['x'][0], 2 - -def check_keyword(error_type, keyword, value): - assert_raises(error_type, ecos.solve, c,G,h,dims, **{keyword: value}) - -def test_failures(): - yield assert_raises, TypeError, ecos.solve - yield assert_raises, TypeError, ecos.solve, c, G, h, dims, A - - yield assert_raises, ValueError, ecos.solve, c, G, h, {'q':[], 'l':0} - yield assert_raises, TypeError, ecos.solve, c, G, h, {'q':[4], 'l':-2} - - yield check_keyword, TypeError, 'verbose', 0 - yield check_keyword, ValueError, 'feastol', 0 - yield check_keyword, ValueError, 'abstol', 0 - yield check_keyword, ValueError, 'reltol', 0 - yield check_keyword, ValueError, 'feastol_inacc', 0 - yield check_keyword, ValueError, 'abstol_inacc', 0 - yield check_keyword, ValueError, 'reltol_inacc', 0 - yield check_keyword, ValueError, 'max_iters', -1 - yield check_keyword, TypeError, 'max_iters', 1.1 +def check_solution(solution, expected): + np.testing.assert_almost_equal(solution, expected, decimal=5) + +@pytest.mark.parametrize("inputs,expected", [ + ((c, G, h, dims, {'feastol': 2e-8, 'reltol': 2e-8, 'abstol': 2e-8, 'verbose': False}), 4), + ((c, G, h, dims, A, b, {'feastol': 2e-8, 'reltol': 2e-8, 'abstol': 2e-8, 'verbose': False}), 3), + ((c, G, h, {'q': [2], 'l': 0}, {'feastol': 2e-8, 'reltol': 2e-8, 'abstol': 2e-8, 'verbose': False}), 2) +]) +def test_problems(inputs, expected): + sol = ecos.solve(*inputs[:-1], **inputs[-1]) + check_solution(sol['x'][0], expected) + + +def test_call_failures(): + with pytest.raises(TypeError): + ecos.solve() + + with pytest.raises(TypeError): + ecos.solve(c, G, h, dims, A) + + with pytest.raises(ValueError): + ecos.solve(c, G, h, {'q':[], 'l':0}) + + with pytest.raises(TypeError): + ecos.solve(c, G, h, {'q':[4], 'l':-2}) + + +@pytest.mark.parametrize("error_type,keyword,value", [ + (TypeError, 'verbose', 0), + (ValueError, 'feastol', 0), + (ValueError, 'abstol', 0), + (ValueError, 'reltol', 0), + (ValueError, 'feastol_inacc', 0), + (ValueError, 'abstol_inacc', 0), + (ValueError, 'reltol_inacc', 0), + (ValueError, 'max_iters', -1), + (TypeError, 'max_iters', 1.1), +]) +def test_keyword_errors(error_type, keyword, value): + with pytest.raises(error_type): + ecos.solve(c, G, h, dims, **{keyword: value}) diff --git a/src/test_interface_bb.py b/src/test_interface_bb.py index a4aba46..48a5c0f 100644 --- a/src/test_interface_bb.py +++ b/src/test_interface_bb.py @@ -1,4 +1,3 @@ -from __future__ import print_function import ecos import numpy as np import scipy.sparse as sp @@ -17,8 +16,6 @@ sol = ecos.solve(c, G, h, dims, verbose=False, mi_verbose=False, int_vars_idx=bool_idx) -print(sol['x']) - c = np.array([-1., -1.]) h = np.array([ 4., 12., 0., 0.]) bool_idx = [] @@ -33,8 +30,6 @@ sol = ecos.solve(c, G, h, dims, verbose=False, mi_verbose=False, int_vars_idx=bool_idx) -print(sol['x']) - c = np.array([-1., -1.1]) h = np.array([ 4., 12., 0., 0.]) bool_idx = [1,0] @@ -49,8 +44,6 @@ sol = ecos.solve(c, G, h, dims, verbose=False, mi_verbose=False, int_vars_idx=bool_idx) -print(sol['x']) - c = np.array([-1., -1.5]) h = np.array([ 4., 12., 0. , 0.]) @@ -64,6 +57,4 @@ dims = dict() dims['l'] = 4 -sol = ecos.solve(c, G, h, dims, verbose=False, mi_verbose=True, bool_vars_idx=bool_idx) -print(sol) -print(sol['x']) +sol = ecos.solve(c, G, h, dims, verbose=False, mi_verbose=True, bool_vars_idx=bool_idx) \ No newline at end of file