From 2816616c934f9a6b804b8a61539d470f664f799b Mon Sep 17 00:00:00 2001 From: Felipe Date: Tue, 26 Mar 2024 15:36:51 -0700 Subject: [PATCH 1/5] Add py12 support --- .github/workflows/end_to_end.yml | 2 +- .github/workflows/minimum.yml | 2 +- .github/workflows/numerical.yml | 2 +- .github/workflows/readme.yml | 2 +- .github/workflows/tutorials.yml | 2 +- .github/workflows/unit.yml | 2 +- pyproject.toml | 18 ++++++++++++------ tests/unit/bivariate/test_base.py | 10 +++++----- tests/unit/multivariate/test_gaussian.py | 12 ++++++++---- tox.ini | 2 +- ...4_Syntehtic_Data_for_Machine_Learning.ipynb | 4 ++-- 11 files changed, 34 insertions(+), 24 deletions(-) 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/pyproject.toml b/pyproject.toml index ac4adb2b..3ae918b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,22 +12,26 @@ 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'", + 'setuptools>=69', ] [project.urls] @@ -47,14 +51,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 +70,8 @@ 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', + 'pyzmq>=25.1.2', # docs 'm2r>=0.2.0,<0.3', 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/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..9bc86154 100644 --- a/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb +++ b/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb @@ -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)" ] }, From 32cbf3ad07d8a4e76bb317c234ee5ad581c9c804 Mon Sep 17 00:00:00 2001 From: Felipe Date: Tue, 26 Mar 2024 19:33:05 -0700 Subject: [PATCH 2/5] Remove and see what happens --- pyproject.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3ae918b3..fdb51a1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ dependencies = [ "scipy>=1.5.4,<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'", - 'setuptools>=69', + 'setuptools<70', ] [project.urls] @@ -71,7 +71,6 @@ dev = [ 'build>=1.0.0,<2', 'bump-my-version>=0.18.3,<1', 'watchdog>=1.0.1,<5', - 'pyzmq>=25.1.2', # docs 'm2r>=0.2.0,<0.3', @@ -170,7 +169,6 @@ namespaces = false '*.png', '*.gif' ] -'tests' = ['*'] [tool.setuptools.exclude-package-data] '*' = [ From 421d07afe52573261854c6eb4ddc528cfd8e5256 Mon Sep 17 00:00:00 2001 From: Felipe Date: Thu, 28 Mar 2024 08:21:56 -0700 Subject: [PATCH 3/5] Remove setuptools + rerun jupyter --- copulas/__init__.py | 10 +- pyproject.toml | 1 - tests/unit/test___init__.py | 14 +- ..._Syntehtic_Data_for_Machine_Learning.ipynb | 438 +++++++++++++++++- 4 files changed, 443 insertions(+), 20 deletions(-) diff --git a/copulas/__init__.py b/copulas/__init__.py index ac91762b..13ff79bc 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 fdb51a1e..a9f5429b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,6 @@ dependencies = [ "scipy>=1.5.4,<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'", - 'setuptools<70', ] [project.urls] 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/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb b/tutorials/04_Syntehtic_Data_for_Machine_Learning.ipynb index 9bc86154..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": [ @@ -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, From 6c6c1c2efb80f39b1bd7abd091d2c55ec415d1b1 Mon Sep 17 00:00:00 2001 From: Felipe Date: Fri, 29 Mar 2024 09:11:57 -0700 Subject: [PATCH 4/5] Attempt to use select for entry_points --- copulas/__init__.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/copulas/__init__.py b/copulas/__init__.py index 13ff79bc..619d2230 100644 --- a/copulas/__init__.py +++ b/copulas/__init__.py @@ -311,13 +311,7 @@ def _get_addon_target(addon_path_name): def _find_addons(): """Find and load all copulas add-ons.""" group = 'copulas_modules' - 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: + for entry_point in entry_points().select(group=group): try: addon = entry_point.load() except Exception: # pylint: disable=broad-exception-caught From ab205cce6859cbd5414efb50e9548123ddd64d6d Mon Sep 17 00:00:00 2001 From: Felipe Date: Fri, 29 Mar 2024 09:20:48 -0700 Subject: [PATCH 5/5] Revert last commit --- copulas/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/copulas/__init__.py b/copulas/__init__.py index 619d2230..a1f2b7d5 100644 --- a/copulas/__init__.py +++ b/copulas/__init__.py @@ -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 entry_points().select(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