Repository: PyEllips/pyElli (language: python)

Issue:
Proper dependency management
Introduce better dependency management to not run in any dependency issues.
Either use [poetry](https://python-poetry.org), [pipenv](https://pypi.org/project/pipenv/) or specify version in requirements.txt with `pip freeze > requirements.txt` or add an additional requirements.freeze.txt.

This includes offering better install options for the optional fitting part. I think we should have something like `pip install pyElli[fitting]`.


Discussion / hints:

Fix patch:
diff --git a/dev-requirements.txt b/dev-requirements.txt
new file mode 100644
index 00000000..ae0f1695
--- /dev/null
+++ b/dev-requirements.txt
@@ -0,0 +1,273 @@
+#
+# This file is autogenerated by pip-compile with python 3.9
+# To update, run:
+#
+#    pip-compile --extra=plot --extra=testing --output-file=dev-requirements.txt
+#
+appnope==0.1.3
+    # via
+    #   ipykernel
+    #   ipython
+argon2-cffi==21.3.0
+    # via notebook
+argon2-cffi-bindings==21.2.0
+    # via argon2-cffi
+asteval==0.9.27
+    # via lmfit
+asttokens==2.0.8
+    # via stack-data
+attrs==22.1.0
+    # via
+    #   jsonschema
+    #   pytest
+backcall==0.2.0
+    # via ipython
+beautifulsoup4==4.11.1
+    # via nbconvert
+bleach==5.0.1
+    # via nbconvert
+cffi==1.15.1
+    # via argon2-cffi-bindings
+coverage[toml]==6.4.4
+    # via pytest-cov
+cycler==0.11.0
+    # via matplotlib
+debugpy==1.6.3
+    # via ipykernel
+decorator==5.1.1
+    # via ipython
+defusedxml==0.7.1
+    # via nbconvert
+entrypoints==0.4
+    # via jupyter-client
+executing==1.0.0
+    # via stack-data
+fastjsonschema==2.16.1
+    # via nbformat
+fonttools==4.37.1
+    # via matplotlib
+future==0.18.2
+    # via uncertainties
+h5py==3.7.0
+    # via pyElli (setup.py)
+importlib-metadata==4.12.0
+    # via nbconvert
+iniconfig==1.1.1
+    # via pytest
+ipykernel==6.15.2
+    # via
+    #   ipywidgets
+    #   nbmake
+    #   notebook
+ipython==8.4.0
+    # via
+    #   ipykernel
+    #   ipywidgets
+    #   pyElli (setup.py)
+ipython-genutils==0.2.0
+    # via
+    #   ipywidgets
+    #   notebook
+ipywidgets==7.7.2
+    # via pyElli (setup.py)
+jedi==0.18.1
+    # via ipython
+jinja2==3.1.2
+    # via
+    #   nbconvert
+    #   notebook
+jsonschema==4.15.0
+    # via nbformat
+jupyter-client==7.3.5
+    # via
+    #   ipykernel
+    #   nbclient
+    #   notebook
+jupyter-core==4.11.1
+    # via
+    #   jupyter-client
+    #   nbconvert
+    #   nbformat
+    #   notebook
+jupyterlab-pygments==0.2.2
+    # via nbconvert
+jupyterlab-widgets==1.1.1
+    # via ipywidgets
+kiwisolver==1.4.4
+    # via matplotlib
+lmfit==1.0.3
+    # via pyElli (setup.py)
+lxml==4.9.1
+    # via nbconvert
+markupsafe==2.1.1
+    # via
+    #   jinja2
+    #   nbconvert
+matplotlib==3.5.3
+    # via pyElli (setup.py)
+matplotlib-inline==0.1.6
+    # via
+    #   ipykernel
+    #   ipython
+mistune==2.0.4
+    # via nbconvert
+nbclient==0.6.7
+    # via
+    #   nbconvert
+    #   nbmake
+nbconvert==7.0.0
+    # via notebook
+nbformat==5.4.0
+    # via
+    #   nbclient
+    #   nbconvert
+    #   nbmake
+    #   notebook
+nbmake==1.3.4
+    # via pyElli (setup.py)
+nest-asyncio==1.5.5
+    # via
+    #   ipykernel
+    #   jupyter-client
+    #   nbclient
+    #   notebook
+notebook==6.4.12
+    # via widgetsnbextension
+numpy==1.23.2
+    # via
+    #   h5py
+    #   lmfit
+    #   matplotlib
+    #   pandas
+    #   pyElli (setup.py)
+    #   scipy
+packaging==21.3
+    # via
+    #   ipykernel
+    #   matplotlib
+    #   nbconvert
+    #   pytest
+pandas==1.4.4
+    # via pyElli (setup.py)
+pandocfilters==1.5.0
+    # via nbconvert
+parso==0.8.3
+    # via jedi
+pexpect==4.8.0
+    # via ipython
+pickleshare==0.7.5
+    # via ipython
+pillow==9.2.0
+    # via matplotlib
+plotly==5.10.0
+    # via pyElli (setup.py)
+pluggy==1.0.0
+    # via pytest
+prometheus-client==0.14.1
+    # via notebook
+prompt-toolkit==3.0.31
+    # via ipython
+psutil==5.9.1
+    # via ipykernel
+ptyprocess==0.7.0
+    # via
+    #   pexpect
+    #   terminado
+pure-eval==0.2.2
+    # via stack-data
+py==1.11.0
+    # via pytest
+pycparser==2.21
+    # via cffi
+pydantic==1.10.1
+    # via nbmake
+pygments==2.13.0
+    # via
+    #   ipython
+    #   nbconvert
+    #   nbmake
+pyparsing==3.0.9
+    # via
+    #   matplotlib
+    #   packaging
+pyrsistent==0.18.1
+    # via jsonschema
+pytest==7.1.3
+    # via
+    #   nbmake
+    #   pyElli (setup.py)
+    #   pytest-cov
+pytest-cov==3.0.0
+    # via pyElli (setup.py)
+python-dateutil==2.8.2
+    # via
+    #   jupyter-client
+    #   matplotlib
+    #   pandas
+pytz==2022.2.1
+    # via pandas
+pyzmq==23.2.1
+    # via
+    #   ipykernel
+    #   jupyter-client
+    #   notebook
+scipy==1.9.1
+    # via
+    #   lmfit
+    #   pyElli (setup.py)
+send2trash==1.8.0
+    # via notebook
+six==1.16.0
+    # via
+    #   asttokens
+    #   bleach
+    #   python-dateutil
+soupsieve==2.3.2.post1
+    # via beautifulsoup4
+stack-data==0.5.0
+    # via ipython
+tenacity==8.0.1
+    # via plotly
+terminado==0.15.0
+    # via notebook
+tinycss2==1.1.1
+    # via nbconvert
+tomli==2.0.1
+    # via
+    #   coverage
+    #   pytest
+tornado==6.2
+    # via
+    #   ipykernel
+    #   jupyter-client
+    #   notebook
+    #   terminado
+traitlets==5.3.0
+    # via
+    #   ipykernel
+    #   ipython
+    #   ipywidgets
+    #   jupyter-client
+    #   jupyter-core
+    #   matplotlib-inline
+    #   nbclient
+    #   nbconvert
+    #   nbformat
+    #   notebook
+typing-extensions==4.3.0
+    # via pydantic
+uncertainties==3.1.7
+    # via lmfit
+wcwidth==0.2.5
+    # via prompt-toolkit
+webencodings==0.5.1
+    # via
+    #   bleach
+    #   tinycss2
+widgetsnbextension==3.6.1
+    # via ipywidgets
+zipp==3.8.1
+    # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/plot-requirements.txt b/plot-requirements.txt
new file mode 100644
index 00000000..2a9b3e37
--- /dev/null
+++ b/plot-requirements.txt
@@ -0,0 +1,240 @@
+#
+# This file is autogenerated by pip-compile with python 3.9
+# To update, run:
+#
+#    pip-compile --extra=plot --output-file=plot-requirements.txt
+#
+appnope==0.1.3
+    # via
+    #   ipykernel
+    #   ipython
+argon2-cffi==21.3.0
+    # via notebook
+argon2-cffi-bindings==21.2.0
+    # via argon2-cffi
+asteval==0.9.27
+    # via lmfit
+asttokens==2.0.8
+    # via stack-data
+attrs==22.1.0
+    # via jsonschema
+backcall==0.2.0
+    # via ipython
+beautifulsoup4==4.11.1
+    # via nbconvert
+bleach==5.0.1
+    # via nbconvert
+cffi==1.15.1
+    # via argon2-cffi-bindings
+cycler==0.11.0
+    # via matplotlib
+debugpy==1.6.3
+    # via ipykernel
+decorator==5.1.1
+    # via ipython
+defusedxml==0.7.1
+    # via nbconvert
+entrypoints==0.4
+    # via jupyter-client
+executing==1.0.0
+    # via stack-data
+fastjsonschema==2.16.1
+    # via nbformat
+fonttools==4.37.1
+    # via matplotlib
+future==0.18.2
+    # via uncertainties
+h5py==3.7.0
+    # via pyElli (setup.py)
+importlib-metadata==4.12.0
+    # via nbconvert
+ipykernel==6.15.2
+    # via
+    #   ipywidgets
+    #   notebook
+ipython==8.4.0
+    # via
+    #   ipykernel
+    #   ipywidgets
+    #   pyElli (setup.py)
+ipython-genutils==0.2.0
+    # via
+    #   ipywidgets
+    #   notebook
+ipywidgets==7.7.2
+    # via pyElli (setup.py)
+jedi==0.18.1
+    # via ipython
+jinja2==3.1.2
+    # via
+    #   nbconvert
+    #   notebook
+jsonschema==4.15.0
+    # via nbformat
+jupyter-client==7.3.5
+    # via
+    #   ipykernel
+    #   nbclient
+    #   notebook
+jupyter-core==4.11.1
+    # via
+    #   jupyter-client
+    #   nbconvert
+    #   nbformat
+    #   notebook
+jupyterlab-pygments==0.2.2
+    # via nbconvert
+jupyterlab-widgets==1.1.1
+    # via ipywidgets
+kiwisolver==1.4.4
+    # via matplotlib
+lmfit==1.0.3
+    # via pyElli (setup.py)
+lxml==4.9.1
+    # via nbconvert
+markupsafe==2.1.1
+    # via
+    #   jinja2
+    #   nbconvert
+matplotlib==3.5.3
+    # via pyElli (setup.py)
+matplotlib-inline==0.1.6
+    # via
+    #   ipykernel
+    #   ipython
+mistune==2.0.4
+    # via nbconvert
+nbclient==0.6.7
+    # via nbconvert
+nbconvert==7.0.0
+    # via notebook
+nbformat==5.4.0
+    # via
+    #   nbclient
+    #   nbconvert
+    #   notebook
+nest-asyncio==1.5.5
+    # via
+    #   ipykernel
+    #   jupyter-client
+    #   nbclient
+    #   notebook
+notebook==6.4.12
+    # via widgetsnbextension
+numpy==1.23.2
+    # via
+    #   h5py
+    #   lmfit
+    #   matplotlib
+    #   pandas
+    #   pyElli (setup.py)
+    #   scipy
+packaging==21.3
+    # via
+    #   ipykernel
+    #   matplotlib
+    #   nbconvert
+pandas==1.4.4
+    # via pyElli (setup.py)
+pandocfilters==1.5.0
+    # via nbconvert
+parso==0.8.3
+    # via jedi
+pexpect==4.8.0
+    # via ipython
+pickleshare==0.7.5
+    # via ipython
+pillow==9.2.0
+    # via matplotlib
+plotly==5.10.0
+    # via pyElli (setup.py)
+prometheus-client==0.14.1
+    # via notebook
+prompt-toolkit==3.0.31
+    # via ipython
+psutil==5.9.1
+    # via ipykernel
+ptyprocess==0.7.0
+    # via
+    #   pexpect
+    #   terminado
+pure-eval==0.2.2
+    # via stack-data
+pycparser==2.21
+    # via cffi
+pygments==2.13.0
+    # via
+    #   ipython
+    #   nbconvert
+pyparsing==3.0.9
+    # via
+    #   matplotlib
+    #   packaging
+pyrsistent==0.18.1
+    # via jsonschema
+python-dateutil==2.8.2
+    # via
+    #   jupyter-client
+    #   matplotlib
+    #   pandas
+pytz==2022.2.1
+    # via pandas
+pyzmq==23.2.1
+    # via
+    #   ipykernel
+    #   jupyter-client
+    #   notebook
+scipy==1.9.1
+    # via
+    #   lmfit
+    #   pyElli (setup.py)
+send2trash==1.8.0
+    # via notebook
+six==1.16.0
+    # via
+    #   asttokens
+    #   bleach
+    #   python-dateutil
+soupsieve==2.3.2.post1
+    # via beautifulsoup4
+stack-data==0.5.0
+    # via ipython
+tenacity==8.0.1
+    # via plotly
+terminado==0.15.0
+    # via notebook
+tinycss2==1.1.1
+    # via nbconvert
+tornado==6.2
+    # via
+    #   ipykernel
+    #   jupyter-client
+    #   notebook
+    #   terminado
+traitlets==5.3.0
+    # via
+    #   ipykernel
+    #   ipython
+    #   ipywidgets
+    #   jupyter-client
+    #   jupyter-core
+    #   matplotlib-inline
+    #   nbclient
+    #   nbconvert
+    #   nbformat
+    #   notebook
+uncertainties==3.1.7
+    # via lmfit
+wcwidth==0.2.5
+    # via prompt-toolkit
+webencodings==0.5.1
+    # via
+    #   bleach
+    #   tinycss2
+widgetsnbextension==3.6.1
+    # via ipywidgets
+zipp==3.8.1
+    # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/requirements.txt b/requirements.txt
index d6762f5a..57f0aac2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,35 @@
-scipy
-numpy>=1.20
-matplotlib
-pandas>=1.0.0
-ipywidgets<8
-plotly
-lmfit
-h5py
+#
+# This file is autogenerated by pip-compile with python 3.9
+# To update, run:
+#
+#    pip-compile
+#
+asteval==0.9.27
+    # via lmfit
+future==0.18.2
+    # via uncertainties
+h5py==3.7.0
+    # via pyElli (setup.py)
+lmfit==1.0.3
+    # via pyElli (setup.py)
+numpy==1.23.2
+    # via
+    #   h5py
+    #   lmfit
+    #   pandas
+    #   pyElli (setup.py)
+    #   scipy
+pandas==1.4.4
+    # via pyElli (setup.py)
+python-dateutil==2.8.2
+    # via pandas
+pytz==2022.2.1
+    # via pandas
+scipy==1.9.1
+    # via
+    #   lmfit
+    #   pyElli (setup.py)
+six==1.16.0
+    # via python-dateutil
+uncertainties==3.1.7
+    # via lmfit
diff --git a/setup.cfg b/setup.cfg
index 8b528bb9..e3e28784 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -56,6 +56,7 @@ install_requires =
     numpy>=1.20
     pandas>=1.0.0
     lmfit
+    h5py
 
 
 [options.packages.find]
@@ -67,13 +68,18 @@ exclude =
 # Add here additional requirements for extra features, to install with:
 # `pip install pyElli[PDF]` like:
 # PDF = ReportLab; RXP
-PLOT = ipywidgets; plotly; matplotlib; ipython
+plot = 
+    ipython
+    ipywidgets<8
+    plotly
+    matplotlib
 
 # Add here test requirements (semicolon/line-separated)
 testing =
     setuptools
     pytest
     pytest-cov
+    nbmake
 
 [options.entry_points]
 # Add here console scripts like:
diff --git a/tox.ini b/tox.ini
index 6121f88f..2c297c27 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,44 +1,31 @@
 [tox]
-minversion = 3.15
-envlist = default
-isolated_build = True
+envlist = py3{11,10,9,8,7}
+skip_missing_interpreters = true
 
 
 [testenv]
-description = Invoke pytest to run automated tests
-setenv =
-    TOXINIDIR = {toxinidir}
-passenv =
-    HOME
-extras =
-    testing
+envtmpdir = {toxworkdir}/tmp/{envname}
 deps =
-    scipy
-    numpy>=1.20
-    pandas>=1.0.0
-    lmfit
-    plotly
-    ipywidgets
-commands =
-    pytest {posargs}
-    
+    -r dev-requirements.txt
+commands = pytest -v --tb=short --basetemp={envtmpdir} {posargs:tests}
 
 
-[testenv:{build,clean}]
-description =
-    build: Build the package in isolation according to PEP517, see https://github.com/pypa/build
-    clean: Remove old distribution files and temporary build artifacts (./build and ./dist)
-# NOTE: build is still experimental, please refer to the links for updates/issues
-# https://setuptools.readthedocs.io/en/stable/build_meta.html#how-to-use-it
-# https://github.com/pypa/pep517/issues/91
-skip_install = True
-changedir = {toxinidir}
-deps =
-    build: build[virtualenv]
-commands =
-    clean: python -c 'from shutil import rmtree; rmtree("build", True); rmtree("dist", True)'
-    build: python -m build .
-# By default `build` produces wheels, you can also explicitly use the flags `--sdist` and `--wheel`
+[testenv:style]
+deps = pre-commit
+skip_install = true
+commands = pre-commit run --all-files --show-diff-on-failure
+
+
+[testenv:requirements]
+# Be aware that this always uses the system python regardless of env
+deps = pip-tools
+setenv =
+  PYTHONPATH=.
+skip_install = true
+commands = 
+    pip-compile
+    pip-compile --extra=plot --extra=testing --output-file=dev-requirements.txt
+    pip-compile --extra=plot --output-file=plot-requirements.txt
 
 
 [testenv:{docs,doctests,linkcheck}]
@@ -58,19 +45,3 @@ deps =
 commands =
     sphinx-build --color -b {env:BUILD} -d "{env:BUILDDIR}/doctrees" "{env:DOCSDIR}" "{env:BUILDDIR}/{env:BUILD}" {posargs}
 
-
-[testenv:publish]
-description =
-    Publish the package you have been developing to a package index server.
-    By default, it uses testpypi. If you really want to publish your package
-    to be publicly accessible in PyPI, use the `-- --repository pypi` option.
-skip_install = True
-changedir = {toxinidir}
-passenv =
-    TWINE_USERNAME
-    TWINE_PASSWORD
-    TWINE_REPOSITORY
-deps = twine
-commands =
-    python -m twine check dist/*
-    python -m twine upload {posargs:--repository testpypi} dist/*


Test patch:
diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml
index ed2d0537..97355db1 100644
--- a/.github/workflows/pytest.yml
+++ b/.github/workflows/pytest.yml
@@ -25,11 +25,9 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install pytest pytest-cov nbmake
-          pip install -r requirements.txt
       - name: Install module
         run: |
-          pip install .
+          pip install .[plot,testing]
       - name: Test with pytest
         run: |
           pytest --nbmake