Repository: uf3/uf3 (language: python)

Issue:
UF3 PyPi Setup
This PR introduces the required changes to publish the package automatically to PyPi:

1. Gather all the modules and submodules correctly in `setup.py`
2. Link this repository as the project website
3. Add `__init__py` to `uf3.forcefield.properties`
4. Add `MANIFEST.in` to upload `requirements.txt` and `readme.rst` correctly
5. Update `requirements.txt` to include all required and optional dependencies. This breaks `pip install -r requirement.txt`, but this step can be omitted as `pip install .` installs requirements automatically.
6. Update tests to use new install mechanism (No more manual dependency installing)
7. Add script to automatically publish to PyPi. This step can be extended to fetch the release number from the GitHub release if the pipeline works correctly.

To complete the setup, a PyPi account secret needs to be configured in GitHub. This secret needs to have full account privileges for the first release, but can then be adapted to only allow access to the correct package.

A demo of the pipeline has been tested in https://github.com/henk789/uf3 and is available at https://test.pypi.org/project/uf3/.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/publish_pypi_package.yml b/.github/workflows/publish_pypi_package.yml
new file mode 100644
index 00000000..5f11fa95
--- /dev/null
+++ b/.github/workflows/publish_pypi_package.yml
@@ -0,0 +1,39 @@
+# This workflow will upload a Python Package using Twine when a release is created
+# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
+
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+name: Upload Python Package to PyPi
+
+on:
+  release:
+    types: [published]
+
+permissions:
+  contents: read
+
+jobs:
+  deploy:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v3
+    - name: Set up Python
+      uses: actions/setup-python@v3
+      with:
+        python-version: '3.x'
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install build
+    - name: Build package
+      run: python -m build
+    - name: Publish package
+      uses: pypa/gh-action-pypi-publish@release/v1
+      with:
+        user: __token__
+        password: ${{ secrets.PYPI_API_TOKEN }}
\ No newline at end of file
diff --git a/MAINFEST.in b/MAINFEST.in
new file mode 100644
index 00000000..34e6b569
--- /dev/null
+++ b/MAINFEST.in
@@ -0,0 +1,2 @@
+include requirements.txt
+include readme.rst
\ No newline at end of file
diff --git a/readme.rst b/readme.rst
index e2427be7..0f129110 100644
--- a/readme.rst
+++ b/readme.rst
@@ -24,16 +24,28 @@ new issues for feature requests and bug reports.
 Setup
 -----
 
+.. Recommended: Install UF3 in a new conda environment:
+
+.. .. code:: bash
+
+..    conda create -n uf3_env python=3.8
+..    conda activate uf3_env
+
+UF3 can be installed in two different ways:
+
+1. Download and install automatically from PyPI (recommended):
+
+.. code:: bash
+
+   pip install uf3
+
+2. Download and install manually from GitHub:
+
 .. code:: bash
 
-   conda create --name uf3_env python=3.7
-   conda activate uf3_env
    git clone https://github.com/uf3/uf3.git
    cd uf3
-   pip install wheel
-   pip install -r requirements.txt
-   pip install numba
-   pip install -e .
+   pip install .
 
 Getting Started
 ---------------
@@ -54,15 +66,13 @@ Elastic constants:
 ::
 
    pip install setuptools_scm
-   pip install "elastic>=5.1.0.17"
+   pip install uf3[elastic_constants]
 
 Phonon spectra:
 
 ::
 
-   pip install spglib
-   pip install seekpath
-   pip install "phonopy>=2.6.0"
+   pip install uf3[phonon_spectra]
 
 LAMMPS interface:
 
@@ -83,6 +93,12 @@ Dependencies
    training.
 -  B-spline evaluations use scipy, numba, and ndsplines.
 -  PyTables is used for reading/writing HDF5 files.
+-  Matplotlib is used for plotting.
+-  We use sklearn for regression.
+-  We use tqdm for progress bars.
+-  We use plotly for interactive plots.
+-  We use PyYaml for configuration files.
+-  We use numpy for array operations.
 
 
 .. |Tests| image:: https://github.com/uf3/uf3/workflows/Tests/badge.svg
diff --git a/requirements.txt b/requirements.txt
index fc05c3fc..d6bd3783 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,9 +1,19 @@
-numpy<1.22
-scipy
-tqdm
 ase
-pandas
-pyyaml
 matplotlib
-ndsplines==0.1.2
+ndsplines
+numba
+numpy
+pandas
+plotly
+PyYAML
+sklearn
+scipy
 tables
+tqdm
+EXTRAS_REQUIRE
+-ELASTIC_CONSTANTS
+elastic
+-PHONON_SPECTRA
+phonopy>=2.6.0
+seekpath
+spglib
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 2ad60487..3fd23306 100644
--- a/setup.py
+++ b/setup.py
@@ -8,29 +8,39 @@
 with open(os.path.join(module_dir, 'readme.rst'), "r") as f:
     long_description = f.read()
 
-install_requires = ['numpy<1.22',
-                    'scipy',
-                    'pandas',
-                    'ase>=3.20.1']
-test_requires = ['pytest']
+with open("requirements.txt", "r") as f:
+    requires = f.readlines()
+    install_requires = requires[:requires.index("EXTRAS_REQUIRE\n")]
+    extras_require = {}
+    extra = ""
+    for extra_require in requires[requires.index("EXTRAS_REQUIRE\n") + 1:]:
+        if extra_require.startswith("-"):
+            extra = extra_require.strip().lstrip("-")
+            continue
+        if extra in extras_require:
+            extras_require[extra].append(extra_require)
+        else:
+            extras_require[extra] = [extra_require]
 
+test_requires = ['pytest']
 
 if __name__ == "__main__":
     setuptools.setup(
         name='uf3',
-        version='0.3',
+        version='0.3.1',
         description='Ultra-Fast Force Fields for molecular dynamics',
         long_description=long_description,
-        url='https://github.com/sxie22/uf3',
+        url='https://github.com/uf3/uf3',
         author='Stephen R. Xie, Matthias Rupp',
         author_email='sxiexie@ufl.edu',
         license='Apache 2.0',
-        packages=['uf3'],
+        packages=setuptools.find_packages(exclude=["tests"]),
         install_requires=install_requires,
+        extras_require=extras_require,
         classifiers=["Programming Language :: Python :: 3.7",
                      'Development Status :: 3 - Alpha',
                      'Intended Audience :: Science/Research',
                      'Operating System :: OS Independent',
                      'Topic :: Scientific/Engineering'],
         tests_require=test_requires,
-    )
+    )
\ No newline at end of file
diff --git a/uf3/forcefield/properties/__init__.py b/uf3/forcefield/properties/__init__.py
new file mode 100644
index 00000000..e69de29b


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2ebf13cb..e9bb36e2 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -38,15 +38,8 @@ jobs:
         gcc -v
         python --version
         pip install -U pip pytest
-        pip install wheel
-        pip install -r requirements.txt
-        pip install numba
-        pip install .
         pip install setuptools_scm
-        # pip install elastic>=5.1.0.17 --no-deps  # Dependency issues with docutils on 11/04/2021 but not reproducible on local machine.
-        pip install spglib
-        pip install seekpath
-        pip install phonopy==2.11.0
+        pip install .[ELASTIC_CONSTANTS,PHONON_SPECTRA]
     - name: Test with pytest
       run: |
-        pytest
+        pytest
\ No newline at end of file