Repository: UC-Davis-molecular-computing/nuad (language: python)

Issue:
Fixes #139; make PyPI package that does not include NUPACK or ViennaRNA
## Description
Add setuptools files to make dsd a PyPI package

## Related Issue
#139

## How Has This Been Tested?

Tested package deployment and installation

### Deployment on TestPyPI:
```
python3.8 setup.py sdist
twine upload --repository testpypi dist/*
```
Result: https://test.pypi.org/project/dsd/0.0.1.1/ (note that version 0.0.1.1 is a version used for test, but in the real package, we will use version 0.0.1)

### Installation:
#### Create Virtual Environment
These directions work for Linux. Directions for Windows/MacOS may vary.
1. Created a new directory.
2. Inside new directory run: `python3.8 -m venv .`
3. Inside of `bin/activate` add `export PYTHONPATH=""` at end of file in order to clear PYTHONPATH so that the virtual environment does not have access to the local dsd.
4. Run `source /bin/activate` to start the virtual environment

#### Test pip install in virtual environment
The following command which mocks `pip install dsd`
```
pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple --no-cache-dir  dsd==0.0.1.1
```
Without nupack, an error occurs:
```
ERROR: Could not find a version that satisfies the requirement nupack (from dsd) (from versions: none)
ERROR: No matching distribution found for nupack
```
After [installing nupack](https://docs.nupack.org/start/#maclinux-installation), rerunning the pip install command results in success. Also ran `import dsd` on python shell and verified no errors occur.

For reference, the command for installing nupack on Linux is (exact file path of nupack may vary):
```
pip install nupack -f ~/Downloads/nupack-4.0.0.27/package
```

## Next Steps

Rather than uploading to PyPI manually, I suggest waiting until I set up the release workflow, which will take care of publishing to PyPI (See #138)

added more doc details about subdomain and dependent fields

Correct installation instructions for OSX
See https://apple.stackexchange.com/questions/51036/what-is-the-difference-between-bash-profile-and-bashrc

On OSX, the terminal runs a login shell, meaning ~/.bash_profile is executed instead of ~/.bashrc. Instructions should say to add PYTHONPATH export line in ~/.bash_profile on OSX instead of ~/.bashrc.
make PyPI package that does not include NUPACK or ViennaRNA
Before figuring out #12, an easier thing to implement would be a PyPI package that does not include NUPACK or ViennaRNA. This would slightly simplify the instructions for installation, even though it would remain necessary to install NUPACK and ViennaRNA to use most pre-packaged constraints.

I recall that NUPACK has some dependencies that are not automatically installed when the nupack Python package is installed, for example matplotlib and scipy. Let's do a clean install (maybe use Python virtual environments to test this out https://docs.python.org/3/tutorial/venv.html) to determine what these packages are and include them as dependencies for dsd. 


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml
index b6281a9b..82bbc405 100644
--- a/.github/workflows/docs-check.yml
+++ b/.github/workflows/docs-check.yml
@@ -5,19 +5,25 @@ on: pull_request
 jobs:
   docs:
     runs-on: ubuntu-latest
+    container:
+      image: unhumbleben/nupack:latest
     steps:
     - uses: actions/checkout@v2.3.4
     - name: Set up Python
       uses: actions/setup-python@v2
       with:
-          python-version: '3.x'
+          python-version: '3.9'
+    - name: Upgrade pip
+      run: python -m pip install --upgrade pip
+    - name: Install NUPACK
+      run: |
+        python -m pip install -U nupack -f /nupack/package
     # got from here: https://github.com/marketplace/actions/python-dependency-installation
     # should install dependencies in requirements.txt
     - name: Install Python dependencies
       uses: py-actions/py-dependency-install@v2
     - name: Install Sphinx
       run: |
-        python -m pip install --upgrade pip
         pip install sphinx sphinx_rtd_theme
     - name: Move to docs folder and build
       run: |
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 00000000..842ea09d
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include requirements.txt
+include LICENSE
\ No newline at end of file
diff --git a/dsd/__version__.py b/dsd/__version__.py
new file mode 100644
index 00000000..993a950d
--- /dev/null
+++ b/dsd/__version__.py
@@ -0,0 +1,1 @@
+version = '0.0.1'  # version line; WARNING: do not remove or change this line or comment
diff --git a/requirements.txt b/requirements.txt
index b106c487..d0fc39c5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,4 +4,5 @@ ordered_set
 pathos
 scadnano
 xlwt
-xlrd
\ No newline at end of file
+xlrd
+nupack
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 00000000..40a85687
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,48 @@
+from setuptools import setup
+from os import path
+
+
+# this is ugly, but appears to be standard practice:
+# https://stackoverflow.com/questions/17583443/what-is-the-correct-way-to-share-package-version-with-setup-py-and-the-package/17626524#17626524
+def extract_version(filename: str):
+    with open(filename) as f:
+        lines = f.readlines()
+    version_comment = '# version line; WARNING: do not remove or change this line or comment'
+    for line in lines:
+        if version_comment in line:
+            idx = line.index(version_comment)
+            line_prefix = line[:idx]
+            parts = line_prefix.split('=')
+            parts = [part.strip() for part in parts]
+            version_str = parts[-1]
+            version_str = version_str.replace('"', '')
+            version_str = version_str.replace("'", '')
+            version_str = version_str.strip()
+            return version_str
+    raise AssertionError(f'could not find version in {filename}')
+
+
+version = extract_version('dsd/__version__.py')
+print(f'dsd version = {version}')
+
+with open("requirements.txt") as fp:
+    install_requires = fp.read().strip().split("\n")
+
+# read the contents of your README file
+this_directory = path.abspath(path.dirname(__file__))
+with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
+    long_description = f.read()
+
+setup(name='dsd',
+      packages=['dsd'],
+      version=version,
+      license='MIT',
+      description="dsd stands for \"DNA sequence designer\". Enables one to specify constraints on a DNA nanostructure made from synthetic DNA and then attempts to find concrete DNA sequences that satisfy the constraints.",
+      author="David Doty",
+      author_email="doty@ucdavis.edu",
+      url="https://github.com/UC-Davis-molecular-computing/dsd",
+      long_description=long_description,
+      long_description_content_type='text/markdown; variant=GFM',
+      python_requires='>=3.7',
+      install_requires=install_requires
+      )


Test patch:
diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml
index 8ca9d615..6e3c7651 100644
--- a/.github/workflows/run_unit_tests.yml
+++ b/.github/workflows/run_unit_tests.yml
@@ -9,6 +9,8 @@ jobs:
   build:
 
     runs-on: ubuntu-latest
+    container:
+      image: unhumbleben/nupack:latest
     strategy:
       matrix:
         python-version: [3.7, 3.8, 3.9]
@@ -19,9 +21,13 @@ jobs:
       uses: actions/setup-python@v2
       with:
         python-version: ${{ matrix.python-version }}
+    - name: Upgrade pip
+      run: python -m pip install --upgrade pip
+    - name: Install NUPACK
+      run: |
+        python -m pip install -U nupack -f /nupack/package
     - name: Install dependencies
       run: |
-        python -m pip install --upgrade pip
         if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
     - name: Test with unittest
       run: |