Repository: mne-tools/mne-python

Issue:
`mne` depends on `setuptools` without declaring it as a dependecy, which can break build backends other than `setuptools`
### Description of the problem

Without declaring `setuptools` as a dependency, `mne` imports `pkg_resources`, which is a part of `setuptools`, in at least one place:

```
File "/tmp/pip-build-env-t3o1ln7x/normal/lib/python3.9/site-packages/mne/datasets/eegbci/eegbci.py", line 8, in <module>
          import pkg_resources
```

In my case this leads to the following problem: I have written a package that depends on `mne` and that I package with `flit`, i.e. my package is fully independent of `setuptools`. When I try to install my package (with the `flit_core` build backend instead of `setuptools`) I get the following error:

```
pip install .[test]
Processing /home/pzr
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Installing backend dependencies ... done
  Preparing metadata (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Preparing metadata (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [38 lines of output]
      Unexpected names under [project]: requires_python
      [pyhelpers] SSL verification check: SSL verification failed.
      [pyhelpers] Adding FhG certificate bundle to the certificate store.
      [pyhelpers] Checking again: SSL verification works, continuing.
      Traceback (most recent call last):
        File "/usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 363, in <module>
          main()
        File "/usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 345, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
        File "/usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 164, in prepare_metadata_for_build_wheel
          return hook(metadata_directory, config_settings)
        File "/tmp/pip-build-env-t3o1ln7x/overlay/lib/python3.9/site-packages/flit_core/buildapi.py", line 49, in prepare_metadata_for_build_wheel
          metadata = make_metadata(module, ini_info)
        File "/tmp/pip-build-env-t3o1ln7x/overlay/lib/python3.9/site-packages/flit_core/common.py", line 410, in make_metadata
          md_dict.update(get_info_from_module(module, ini_info.dynamic_metadata))
        File "/tmp/pip-build-env-t3o1ln7x/overlay/lib/python3.9/site-packages/flit_core/common.py", line 207, in get_info_from_module
          docstring, version = get_docstring_and_version_via_import(target)
        File "/tmp/pip-build-env-t3o1ln7x/overlay/lib/python3.9/site-packages/flit_core/common.py", line 180, in get_docstring_and_version_via_import
          spec.loader.exec_module(m)
        File "<frozen importlib._bootstrap_external>", line 850, in exec_module
        File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
        File "/home/pzr/src/pyhelpers/__init__.py", line 3, in <module>
          from . import constants, fileio, neuro, plotting, sigproc, string
        File "/home/pzr/src/pyhelpers/sigproc/__init__.py", line 1, in <module>
          from . import eeg
        File "/home/pzr/src/pyhelpers/sigproc/eeg/__init__.py", line 1, in <module>
          from ._eeg import (create_eeg_raw_array, drop_channels, filter_eeg,
        File "/home/pzr/src/pyhelpers/sigproc/eeg/_eeg.py", line 4, in <module>
          from mne import create_info
        File "/tmp/pip-build-env-t3o1ln7x/normal/lib/python3.9/site-packages/mne/__init__.py", line 111, in <module>
          from . import datasets
        File "/tmp/pip-build-env-t3o1ln7x/normal/lib/python3.9/site-packages/mne/datasets/__init__.py", line 10, in <module>
          from . import eegbci
        File "/tmp/pip-build-env-t3o1ln7x/normal/lib/python3.9/site-packages/mne/datasets/eegbci/__init__.py", line 3, in <module>
          from .eegbci import data_path, load_data, standardize
        File "/tmp/pip-build-env-t3o1ln7x/normal/lib/python3.9/site-packages/mne/datasets/eegbci/eegbci.py", line 8, in <module>
          import pkg_resources
      ModuleNotFoundError: No module named 'pkg_resources'
      [end of output]
```

The problem is solved by declaring `setuptools` as a dependency in my own package, which I would prefer not having to do for obvious reasons. I understand that `setuptools` has been the de-facto standard for many years and that one could just assume that pretty much every package will be installed in an environment where it is present. But lately a lot of people have been moving away from `setuptools`, so if you depend on it I think you should explicitly declare it as a dependency in `mne`.

### Steps to reproduce

Write a package with a build backend other than `setuptools` and have it depend on `mne`.


### Link to data

_No response_

### Expected results

Package can be installed with build backend other than `setuptools`.

### Actual results

Package can't be installed.

### Additional information

(This is on a Gitlab runner, so not sure how helpful this is)

```
Platform:         Linux-3.10.0-1160.15.2.el7.x86_64-x86_64-with-glibc2.31
Python:           3.9.16 (main, Jan 23 2023, 23:35:25)  [GCC 10.2.1 20210110]
Executable:       /usr/local/bin/python
CPU:              : 20 cores
Memory:           Unavailable (requires "psutil" package)
mne:              1.3.0
numpy:            1.24.1 {unknown linalg bindings (threadpoolctl module not found: No module named 'threadpoolctl')}
scipy:            1.10.0
matplotlib:       3.6.3 {backend=agg}

sklearn:          Not found
numba:            Not found
nibabel:          Not found
nilearn:          Not found
dipy:             Not found
openmeeg:         Not found
cupy:             Not found
pandas:           Not found
pyvista:          Not found
pyvistaqt:        Not found
ipyvtklink:       Not found
vtk:              Not found
qtpy:             Not found
ipympl:           Not found
pyqtgraph:        Not found
pooch:            v1.6.0

mne_bids:         Not found
mne_nirs:         Not found
mne_features:     Not found
mne_qt_browser:   Not found
mne_connectivity: Not found
mne_icalabel:     Not found
```


Discussion:
Hello! 👋 Thanks for opening your first issue here! ❤️ We will try to get back to you soon. 🚴🏽‍♂️

I think we should try to replace `setuptools.pkg_resources` with `importlib.resources` (which is part of the standard library) (as recommended [here](https://setuptools.pypa.io/en/latest/pkg_resources.html)). Would that resolve your issue?
I think it should, as it's part of the standard library. I just checked, there's only one additional place where `pkg_resources` is imported (https://github.com/mne-tools/mne-python/blob/main/mne/utils/misc.py#L443), so it should be a fairly easy thing to fix (assuming there are no other parts of `setuptools` that are used somewhere in `mne`). 

I have no experience with Github pull requests (we're using Gitlab at my company) but I'm happy to read up on it and give it a try.
> I have no experience with Github pull requests (we're using Gitlab at my company) but I'm happy to read up on it and give it a try.

please go for it!
While trying to set up my local environment according to https://mne.tools/stable/install/contributing.html I ran into a problem when installing the doc requirements. Not sure if this is relevant in the context of this issue (I will ignore this for the moment), but thought I'd mention it.

```
 pzr@ols122 ~\development\mne-python main  ❯ python -m pip install -r .\requirements_doc.txt
Collecting https://github.com/numpy/numpydoc/archive/main.zip (from -r .\requirements_doc.txt (line 3))
  Downloading https://github.com/numpy/numpydoc/archive/main.zip
     | 86.9 kB 174.9 kB/s 0:00:00
  Preparing metadata (setup.py) ... done
Collecting https://github.com/pydata/pydata-sphinx-theme/archive/f367a58af33be362351686f1e207ea099f8e529e.zip (from -r .\requirements_doc.txt (line 4))
  Downloading https://github.com/pydata/pydata-sphinx-theme/archive/f367a58af33be362351686f1e207ea099f8e529e.zip
     / 3.4 MB 584.2 kB/s 0:00:05
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Preparing metadata (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [16 lines of output]
      Traceback (most recent call last):
        File "C:\Users\pzr\development\venv\mne-bugfix-38\lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py", line 353, in <module>
          main()
        File "C:\Users\pzr\development\venv\mne-bugfix-38\lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py", line 335, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
        File "C:\Users\pzr\development\venv\mne-bugfix-38\lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py", line 149, in prepare_metadata_for_build_wheel
          return hook(metadata_directory, config_settings)
        File "C:\Users\pzr\AppData\Local\Temp\pip-build-env-el1y8v1d\overlay\Lib\site-packages\sphinx_theme_builder\__init__.py", line 80, in prepare_metadata_for_build_wheel
          return _generate_metadata(project, destination=Path(metadata_directory))
        File "C:\Users\pzr\AppData\Local\Temp\pip-build-env-el1y8v1d\overlay\Lib\site-packages\sphinx_theme_builder\_internal\distributions.py", line 132, in generate_metadata
          (dist_info / "METADATA").write_text(project.get_metadata_file_contents())
        File "C:\Users\pzr\AppData\Local\Programs\Python\Python38\lib\pathlib.py", line 1256, in write_text
          return f.write(data)
        File "C:\Users\pzr\AppData\Local\Programs\Python\Python38\lib\encodings\cp1252.py", line 19, in encode
          return codecs.charmap_encode(input,self.errors,encoding_table)[0]
      UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f4da' in position 4769: character maps to <undefined>
      [end of output]
```
Exporting the environment variable `PYTHONUTF8=1` before install should fix this. Windows doesn't like the fact that there are emoji in the README of our website theme

Resolving patch:
diff --git a/mne/datasets/eegbci/eegbci.py b/mne/datasets/eegbci/eegbci.py
--- a/mne/datasets/eegbci/eegbci.py
+++ b/mne/datasets/eegbci/eegbci.py
@@ -4,13 +4,18 @@
 # License: BSD Style.
 
 import os
-from os import path as op
-import pkg_resources
 import re
+from os import path as op
 from pathlib import Path
 
-from ..utils import _get_path, _do_path_update
 from ...utils import _url_to_local_path, verbose
+from ..utils import _do_path_update, _get_path
+
+# TODO: remove try/except when our min version is py 3.9
+try:
+    from importlib.resources import files
+except ImportError:
+    from importlib_resources import files
 
 
 EEGMI_URL = 'https://physionet.org/files/eegmmidb/1.0.0/'
@@ -185,8 +190,7 @@ def load_data(subject, runs, path=None, force_update=False, update_path=None,
     )
 
     # load the checksum registry
-    registry = pkg_resources.resource_stream(
-        'mne', op.join('data', 'eegbci_checksums.txt'))
+    registry = files('mne').joinpath('data', 'eegbci_checksums.txt')
     fetcher.load_registry(registry)
 
     # fetch the file(s)
diff --git a/mne/utils/misc.py b/mne/utils/misc.py
--- a/mne/utils/misc.py
+++ b/mne/utils/misc.py
@@ -22,6 +22,12 @@
 from ..utils import _check_option, _validate_type
 from ._logging import logger, verbose, warn
 
+# TODO: remove try/except when our min version is py 3.9
+try:
+    from importlib.resources import files
+except ImportError:
+    from importlib_resources import files
+
 
 def _pl(x, non_pl='', pl='s'):
     """Determine if plural should be used."""
@@ -436,12 +442,7 @@ def _resource_path(submodule, filename):
     path : str
         The full system path to the requested file.
     """
-    try:
-        from importlib.resources import files
-        return files(submodule).joinpath(filename)
-    except ImportError:
-        from pkg_resources import resource_filename
-        return resource_filename(submodule, filename)
+    return files(submodule).joinpath(filename)
 
 
 def repr_html(f):


Test patch: