diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 11382490..a7ad18f3 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -10,10 +10,10 @@ 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 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fd795acc..84bf0f1d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Set up Python 3.9 uses: actions/setup-python@v2 with: diff --git a/.github/workflows/minimum.yml b/.github/workflows/minimum.yml index 3ea44860..1d0d9ecc 100644 --- a/.github/workflows/minimum.yml +++ b/.github/workflows/minimum.yml @@ -10,10 +10,10 @@ 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 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml index 77be4345..dcc4389f 100644 --- a/.github/workflows/readme.yml +++ b/.github/workflows/readme.yml @@ -10,10 +10,10 @@ 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] # skip windows bc rundoc fails steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index db025c6f..b031ebe6 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -10,10 +10,10 @@ 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 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: diff --git a/INSTALL.md b/INSTALL.md index e938efae..5862ec86 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -3,7 +3,7 @@ ## Requirements **RDT** has been developed and tested on -[Python 3.8, 3.9, 3.10 and 3.11](https://www.python.org/downloads/) +[Python 3.8, 3.9, 3.10, 3.11 and 3.12](https://www.python.org/downloads/) Also, although it is not strictly required, the usage of a [virtualenv]( https://virtualenv.pypa.io/en/latest/) is highly recommended in order to avoid diff --git a/pyproject.toml b/pyproject.toml index 36859937..b9b73562 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,24 +12,28 @@ 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 = ['machine learning', 'synthetic data generation', 'benchmark', 'generative models'] 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;python_version<'3.10'", - "numpy>=1.23.3;python_version>='3.10'", + "numpy>=1.23.3;python_version>='3.10' and python_version<'3.12'", + "numpy>=1.26.0;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'", "scipy>=1.5.4;python_version<'3.10'", - "scipy>=1.9.2;python_version>='3.10'", + "scipy>=1.9.2;python_version>='3.10' and python_version<'3.12'", + "scipy>=1.12.0;python_version>='3.12'", "scikit-learn>=0.24;python_version<'3.10'", "scikit-learn>=1.1.0;python_version>='3.10' and python_version<'3.11'", - "scikit-learn>=1.1.3;python_version>='3.11'", + "scikit-learn>=1.1.3;python_version>='3.11' and python_version<'3.12'", + "scikit-learn>=1.3.0;python_version>='3.12'", 'Faker>=17', ] @@ -44,7 +48,7 @@ dependencies = [ rdt = { main = 'rdt.cli.__main__:main' } [project.optional-dependencies] -copulas = ['copulas>=0.10.0',] +copulas = ['copulas@git+https://git@github.com/sdv-dev/copulas.git',] test = [ 'rdt[copulas]', @@ -63,7 +67,7 @@ dev = [ 'build>=1.0.0,<2', 'bump-my-version>=0.18.3,<1', 'pip>=9.0.1', - 'watchdog>=0.8.3,<0.11', + 'watchdog>=1.0.1,<5', # style check 'pycodestyle<2.8.0,>=2.7.0', @@ -133,7 +137,6 @@ namespaces = false '*.png', '*.gif' ] -'tests' = ['*'] [tool.setuptools.exclude-package-data] '*' = [ diff --git a/rdt/__init__.py b/rdt/__init__.py index 06b92dbc..c0e3dbfc 100644 --- a/rdt/__init__.py +++ b/rdt/__init__.py @@ -10,12 +10,12 @@ import sys import warnings +from importlib.metadata import entry_points from operator import attrgetter from types import ModuleType import numpy as np import pandas as pd -from pkg_resources import iter_entry_points from rdt import transformers from rdt.hyper_transformer import HyperTransformer @@ -149,7 +149,13 @@ def _find_addons(): from top_module.addon_module import x """ group = 'rdt_modules' - for entry_point in iter_entry_points(group=group): + try: + eps = entry_points(group=group) # pylint: disable=E1123 + 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/tests/unit/test___init__.py b/tests/unit/test___init__.py index db0f8b2d..cd027b66 100644 --- a/tests/unit/test___init__.py +++ b/tests/unit/test___init__.py @@ -56,7 +56,7 @@ def test_get_demo_many_rows(): pd.testing.assert_frame_equal(demo, expected) -@patch.object(rdt, 'iter_entry_points') +@patch.object(rdt, 'entry_points') def test__find_addons_module(entry_points_mock, mock_rdt): """Test loading an add-on.""" # Setup @@ -75,7 +75,25 @@ def test__find_addons_module(entry_points_mock, mock_rdt): assert sys.modules['rdt.submodule.entry_name'] == add_on_mock -@patch.object(rdt, 'iter_entry_points') +@patch.object(rdt, 'entry_points') +def test__find_addons_type_error(entry_points_mock): + """Test it when entry_points raises a TypeError (happens for py38, py39).""" + # Setup + def side_effect(arg=None): + if arg == 'rdt_modules': + raise TypeError() + return {arg: []} + + entry_points_mock.side_effect = side_effect + + # Run + _find_addons() + + # Assert + entry_points_mock.assert_called_with() + + +@patch.object(rdt, 'entry_points') def test__find_addons_object(entry_points_mock, mock_rdt): """Test loading an add-on.""" # Setup @@ -93,7 +111,7 @@ def test__find_addons_object(entry_points_mock, mock_rdt): @patch('warnings.warn') -@patch('rdt.iter_entry_points') +@patch('rdt.entry_points') def test__find_addons_bad_addon(entry_points_mock, warning_mock): """Test failing to load an add-on generates a warning.""" # Setup @@ -116,7 +134,7 @@ def entry_point_error(): @patch('warnings.warn') -@patch('rdt.iter_entry_points') +@patch('rdt.entry_points') def test__find_addons_wrong_base(entry_points_mock, warning_mock): """Test incorrect add-on name generates a warning.""" # Setup @@ -137,7 +155,7 @@ def test__find_addons_wrong_base(entry_points_mock, warning_mock): @patch('warnings.warn') -@patch('rdt.iter_entry_points') +@patch('rdt.entry_points') def test__find_addons_missing_submodule(entry_points_mock, warning_mock): """Test incorrect add-on name generates a warning.""" # Setup @@ -158,7 +176,7 @@ def test__find_addons_missing_submodule(entry_points_mock, warning_mock): @patch('warnings.warn') -@patch('rdt.iter_entry_points') +@patch('rdt.entry_points') def test__find_addons_module_and_object(entry_points_mock, warning_mock): """Test incorrect add-on name generates a warning.""" # Setup @@ -179,7 +197,7 @@ def test__find_addons_module_and_object(entry_points_mock, warning_mock): @patch('warnings.warn') -@patch.object(rdt, 'iter_entry_points') +@patch.object(rdt, 'entry_points') def test__find_addons_missing_object(entry_points_mock, warning_mock, mock_rdt): """Test incorrect add-on name generates a warning.""" # Setup diff --git a/tox.ini b/tox.ini index ff8ce053..245932a9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py39-lint, py39-performance, py3{8,9,10,11}-{readme,unit,integration,minimum} +envlist = py39-lint, py39-performance, py3{8,9,10,11,12}-{readme,unit,integration,minimum} [testenv] skipsdist = false