diff --git a/.github/workflows/end_to_end.yml b/.github/workflows/end_to_end.yml index f9f539db..418e5e97 100644 --- a/.github/workflows/end_to_end.yml +++ b/.github/workflows/end_to_end.yml @@ -10,7 +10,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/minimum.yml b/.github/workflows/minimum.yml index e56b5a5e..832e7f08 100644 --- a/.github/workflows/minimum.yml +++ b/.github/workflows/minimum.yml @@ -10,7 +10,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/numerical.yml b/.github/workflows/numerical.yml index 5c86bcb5..52d0f881 100644 --- a/.github/workflows/numerical.yml +++ b/.github/workflows/numerical.yml @@ -10,7 +10,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml index 4d76f2da..8be604ab 100644 --- a/.github/workflows/readme.yml +++ b/.github/workflows/readme.yml @@ -10,7 +10,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] os: [ubuntu-latest, macos-latest] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/tutorials.yml b/.github/workflows/tutorials.yml index 9673a618..a59f58a7 100644 --- a/.github/workflows/tutorials.yml +++ b/.github/workflows/tutorials.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index b3c73a50..34c35314 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -10,7 +10,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v1 diff --git a/copulas/__init__.py b/copulas/__init__.py index ac91762b..a1f2b7d5 100644 --- a/copulas/__init__.py +++ b/copulas/__init__.py @@ -11,11 +11,11 @@ import sys import warnings from copy import deepcopy +from importlib.metadata import entry_points from operator import attrgetter import numpy as np import pandas as pd -from pkg_resources import iter_entry_points EPSILON = np.finfo(np.float32).eps @@ -311,7 +311,13 @@ def _get_addon_target(addon_path_name): def _find_addons(): """Find and load all copulas add-ons.""" group = 'copulas_modules' - for entry_point in iter_entry_points(group=group): + try: + eps = entry_points(group=group) + except TypeError: + # Load-time selection requires Python >= 3.10 or importlib_metadata >= 3.6 + eps = entry_points().get(group, []) + + for entry_point in eps: try: addon = entry_point.load() except Exception: # pylint: disable=broad-exception-caught diff --git a/pyproject.toml b/pyproject.toml index ac4adb2b..a9f5429b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,22 +12,25 @@ classifiers = [ 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Topic :: Scientific/Engineering :: Artificial Intelligence', ] keywords = [ 'copulas' ] dynamic = ["version"] license = { text = 'BSL-1.1' } -requires-python = '>=3.8,<3.12' +requires-python = '>=3.8,<3.13' readme = 'README.md' dependencies = [ "numpy>=1.20.0,<2;python_version<'3.10'", - "numpy>=1.23.3,<2;python_version>='3.10'", + "numpy>=1.23.3,<2;python_version>='3.10' and python_version<'3.12'", + "numpy>=1.26.0,<2;python_version>='3.12'", "pandas>=1.1.3;python_version<'3.10'", "pandas>=1.3.4;python_version>='3.10' and python_version<'3.11'", "pandas>=1.5.0;python_version>='3.11'", 'plotly>=5.10.0,<6', "scipy>=1.5.4,<2;python_version<'3.10'", - "scipy>=1.9.2,<2;python_version>='3.10'", + "scipy>=1.9.2,<2;python_version>='3.10' and python_version<'3.12'", + "scipy>=1.12.0,<2;python_version>='3.12'", ] [project.urls] @@ -47,14 +50,15 @@ version = {attr = 'copulas.__version__'} [project.optional-dependencies] tutorials = [ 'markupsafe<=2.0.1', - 'scikit-learn>=0.24,<1.2', + "scikit-learn>=0.24,<1.2;python_version<'3.10'", + "scikit-learn>=0.24,<1.5;python_version>='3.10'", 'jupyter>=1.0.0,<2', ] test = [ 'copulas[tutorials]', 'pytest>=6.2.5,<7', 'pytest-cov>=2.6.0,<3', - 'pytest-rerunfailures>=9.0.0,<10', + 'pytest-rerunfailures>=10.3,<15', 'rundoc>=0.4.3,<0.5', 'tomli>=2.0.0,<3', ] @@ -65,7 +69,7 @@ dev = [ 'pip>=9.0.1', 'build>=1.0.0,<2', 'bump-my-version>=0.18.3,<1', - 'watchdog>=0.8.3,<0.11', + 'watchdog>=1.0.1,<5', # docs 'm2r>=0.2.0,<0.3', @@ -164,7 +168,6 @@ namespaces = false '*.png', '*.gif' ] -'tests' = ['*'] [tool.setuptools.exclude-package-data] '*' = [ diff --git a/tests/unit/bivariate/test_base.py b/tests/unit/bivariate/test_base.py index e8513897..0f42fe61 100644 --- a/tests/unit/bivariate/test_base.py +++ b/tests/unit/bivariate/test_base.py @@ -80,7 +80,7 @@ def test_save(self, json_mock, open_mock): instance.save('test.json') # Check - assert open_mock.called_once_with('test.json', 'w') + open_mock.assert_called_once_with('test.json', 'w') assert json_mock.called compare_nested_dicts(json_mock.call_args[0][0], expected_content) @@ -99,10 +99,10 @@ def test_load_from_file(self, json_mock, open_mock): instance = Bivariate.load('somefile.json') # Check - assert open_mock.called_once_with('test.json', 'r') - instance.copula_type == CopulaTypes.FRANK - instance.tau == -0.33333333333333337 - instance.theta == -3.305771759329249 + open_mock.assert_called_once_with('somefile.json') + assert instance.copula_type == CopulaTypes.FRANK + assert instance.tau == -0.33333333333333337 + assert instance.theta == -3.305771759329249 @mock.patch('copulas.bivariate.clayton.Clayton.partial_derivative') def test_partial_derivative_scalar(self, derivative_mock): diff --git a/tests/unit/multivariate/test_gaussian.py b/tests/unit/multivariate/test_gaussian.py index 2e7060b5..7c31e774 100644 --- a/tests/unit/multivariate/test_gaussian.py +++ b/tests/unit/multivariate/test_gaussian.py @@ -392,11 +392,15 @@ def test_sample(self, normal_mock): # Check assert result.equals(expected_result) - assert normal_mock.called_once_with( - np.zeros(instance.correlation.shape[0]), - instance.correlation, - 5 + np.testing.assert_array_equal( + normal_mock.call_args[0][0], + np.zeros(instance.correlation.shape[0]) ) + np.testing.assert_array_equal( + normal_mock.call_args[0][1], + instance.correlation + ) + assert normal_mock.call_args[1] == {'size': 5} def test_sample_random_state(self): """When random_state is set the samples are the same.""" diff --git a/tests/unit/test___init__.py b/tests/unit/test___init__.py index 4d88f5f0..0d21a303 100644 --- a/tests/unit/test___init__.py +++ b/tests/unit/test___init__.py @@ -435,7 +435,7 @@ def mock_copulas(): sys.modules['copulas'] = copulas_module -@patch.object(copulas, 'iter_entry_points') +@patch.object(copulas, 'entry_points') def test__find_addons_module(entry_points_mock, mock_copulas): """Test loading an add-on.""" # Setup @@ -452,7 +452,7 @@ def test__find_addons_module(entry_points_mock, mock_copulas): assert mock_copulas.submodule.entry_name == 'entry_point' -@patch.object(copulas, 'iter_entry_points') +@patch.object(copulas, 'entry_points') def test__find_addons_object(entry_points_mock, mock_copulas): """Test loading an add-on.""" # Setup @@ -470,7 +470,7 @@ def test__find_addons_object(entry_points_mock, mock_copulas): @patch('warnings.warn') -@patch('copulas.iter_entry_points') +@patch('copulas.entry_points') def test__find_addons_bad_addon(entry_points_mock, warning_mock): """Test failing to load an add-on generates a warning.""" # Setup @@ -493,7 +493,7 @@ def entry_point_error(): @patch('warnings.warn') -@patch('copulas.iter_entry_points') +@patch('copulas.entry_points') def test__find_addons_wrong_base(entry_points_mock, warning_mock): """Test incorrect add-on name generates a warning.""" # Setup @@ -514,7 +514,7 @@ def test__find_addons_wrong_base(entry_points_mock, warning_mock): @patch('warnings.warn') -@patch('copulas.iter_entry_points') +@patch('copulas.entry_points') def test__find_addons_missing_submodule(entry_points_mock, warning_mock): """Test incorrect add-on name generates a warning.""" # Setup @@ -535,7 +535,7 @@ def test__find_addons_missing_submodule(entry_points_mock, warning_mock): @patch('warnings.warn') -@patch('copulas.iter_entry_points') +@patch('copulas.entry_points') def test__find_addons_module_and_object(entry_points_mock, warning_mock): """Test incorrect add-on name generates a warning.""" # Setup @@ -556,7 +556,7 @@ def test__find_addons_module_and_object(entry_points_mock, warning_mock): @patch('warnings.warn') -@patch.object(copulas, 'iter_entry_points') +@patch.object(copulas, 'entry_points') def test__find_addons_missing_object(entry_points_mock, warning_mock, mock_copulas): """Test incorrect add-on name generates a warning.""" # Setup diff --git a/tox.ini b/tox.ini index baaff459..633abe92 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py39-lint, py3{8,9,10,11}-{readme,unit,end_to_end,numerical,minimum,tutorials} +envlist = py39-lint, py3{8,9,10,11,12}-{readme,unit,end_to_end,numerical,minimum,tutorials} [testenv] skipsdist = false diff --git a/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb b/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb index 92b7f652..2ccbb879 100644 --- a/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb +++ b/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb @@ -18,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -26,10 +26,10 @@ "\n", "warnings.filterwarnings('ignore')\n", "\n", - "from sklearn.datasets import load_boston\n", + "from sklearn.datasets import load_diabetes\n", "from sklearn.model_selection import train_test_split\n", "\n", - "X, y = load_boston(return_X_y=True)\n", + "X, y = load_diabetes(return_X_y=True)\n", "X_train, X_test, y_train, y_test = train_test_split(X, y)" ] }, @@ -43,7 +43,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -82,9 +82,427 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
ElasticNet()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "ElasticNet()" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from sklearn.linear_model import ElasticNet\n", "\n", @@ -101,14 +519,14 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "0.574182672682398\n" + "0.010323153621473069\n" ] } ], @@ -125,20 +543,20 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "0.5949580051414429\n" + "0.008700399284224392\n" ] } ], "source": [ "model = ElasticNet()\n", - "model.fit(X_train, y_train);\n", + "model.fit(X_train, y_train)\n", "print(model.score(X_test, y_test))" ] }, @@ -166,7 +584,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.9" + "version": "3.12.2" } }, "nbformat": 4,