Skip to content

Commit

Permalink
Merge pull request #7 from MolSSI/apiwrapper
Browse files Browse the repository at this point in the history
Create APIs, standalone API request wrapper and docs.
  • Loading branch information
Lnaden authored Feb 22, 2022
2 parents 185fad8 + 30dc801 commit 8b1c6e1
Show file tree
Hide file tree
Showing 47 changed files with 7,532 additions and 335 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ logs/*
qikprop
QikProp/
staging

sandbox
86 changes: 8 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,83 +15,13 @@ There are two main components for this project:
* A web application where data can be uploaded in the form, and provides the endpoint for the API
* A standalone API wrapper for CLI calls to the service hosted through the web app

How to run and use the Web App for development
==============================================
Please visit each subproject's folder and to see the documentation for each one.

The web app exists in the `webapp` folder of this repository.
Webapp Front End
----------------
The web application and service can be found at https://qikprop.molssi.org.

### 1- Install Python requirements:

Run in shell, create python env, and install requirements:

```bash
conda create -n qikpropservice
conda activate qikpropservice
pip install -r requirements.txt
```


### 2- Install JavaScript requirements:

Next, install Node (front-end), and install JS requirements,
which will be fetched from package.json automatically. In Ubuntu:

```bash
sudo apt-get install nodejs
cd webapp/app/static
npm install
```

### 3- Database setup

1. Install mongodb based on your operating system from
https://docs.mongodb.com/guides/server/install/

2. Create a `webapp/.env` file, and add your DB URI to the config file:
```.env
MONGO_URI='mongodb://usr_username:user_password@localhost:27017/qikpropservice_db'
```

Replace `user_username` and `user_password` with your own values from your installation.
You **don't** have to create a database after your install mongodb because the application will do
it later.


Note: In the future when you need to, add PUBLICLY shared environment attributes to `.flaskenv` file, with key values that will be exported to the environment (dev, prod, etc).
Use `.env` file for private variables that won't be shared or pushed to Github. Note that `.env` overrides `.flaskenv`, and both override `config.py`.



### 4- Run the local server

To run the website locally, use:

```bash
flask run
```


## To Use Docker Compose (instead of the above steps):

Run docker-compose directly, or optionally, change any desired environment variables by creating
a `.env` file which will be read automatically by docker-compose.

** It is very important to make sure that the shared folder has the right user NOT root owner. **

```bash
# create the host volume folder with non-root access
mkdir docker_data
chown -R myUser:myUse docker_data
# clean unused docker images and containers
./dockerclean.sh
# build and run containers
docker-compose up --build
```

## More resources:

1. For Docker deployment config example, check this
https://www.digitalocean.com/community/tutorials/how-to-set-up-flask-with-mongodb-and-docker

2. A service file has been included for getting this running as a service. See this url for more details
https://community.hetzner.com/tutorials/docker-compose-as-systemd-service
CLI and Python Library
----------------------
The CLI tool and Python Library are downloadable through PyPI and Conda-Forge (soon, links and install instruction
available when published)
1 change: 1 addition & 0 deletions apiwrapper/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
qikpropservice/_version.py export-subst
7 changes: 7 additions & 0 deletions apiwrapper/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2022 The Molecular Sciences Software Institute

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 changes: 9 additions & 0 deletions apiwrapper/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
recursive-include qikpropservice *.py *.json *.md

include setup.py
include README.md
include LICENSE
include MANIFEST.in

include versioneer.py
include qikpropservice/_version.py
136 changes: 136 additions & 0 deletions apiwrapper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
[![codecov](https://codecov.io/gh/MolSSI/qikpropservice/branch/master/graph/badge.svg)](https://codecov.io/gh/MolSSI/qikpropservice)

MolSSI QikProp As A Service API Wrapper Library
===============================================

A library which wraps the API calls for the QikProp v3 As A Service

The version of QikProp reached by this library has been provided by [William L. Jorgensen](http://zarbi.chem.yale.edu)
and hosted as a service by the [Molecular Sciences Software Institute (MolSSI)](https://molssi.org/). To report a
problem or suggest improvements, please open an issue on
[the Project GitHub](https://github.com/MolSSI/qikpropservice). Additional features and options will be
added over time.

This project serves as the Python wrapper for making the API calls by providing both an importable
library and a CLI tool to make calls to the QikProp Service.

For direct information regarding the API endpoints, please see
[the Project GitHub](https://github.com/MolSSI/qikpropservice).

Installation From Conda or Pip
------------------------------

This package can be installed from either Conda (via Conda-Forge) or Pip

```bash
conda install -c conda-forge qikpropservice
```
OR
```bash
pip install qikpropservice
```

Installation from Source
------------------------

1. Clone the repo at https://github.com/MolSSI/qikpropservice
2. Navigate to the folder `apiwrapper`
3. Run `python setup.py install`

Usage as a CLI Tool
-------------------

The CLI can be run from any command line interface by invoking

```bash
qikpropcli
```

The CLI provides its own documentation for how to use it, but most commonly can be used as such:

```bash
qikpropcli run FILES
```
Where `FILES` can be replaced with any number of entries of files to submit to the QikProp Service API endpoints.
There are options which can be specified here such as custom URI server's (e.g. for local testing) or QikProp
options, but all of those are documented in the `--help` flag.


Usage as a Python Library
-------------------------

There are two main library functions depending on if you want to do large bulk processing, or more fine-grained
file-by-file processing. In either use case, the library works on on-disk files rather than data pre-read
into memory.

The main helper function is `qikprop_as_a_service` which acts much as the CLI does in that it processes many files
all the same way.

```python
from qikpropservice import qikprop_as_a_service

qikprop_as_a_service("file1.mol, file2.mol, ligand_series*.mol2")
```

This will run the two named files `file1.mol`, `file2.mol` and all the files matching the glob `ligand_series*.mol2`.
It is possible to set the output name of each of the returned `.tar.gz` files through a keyword. Other options such as
what settings that can be passed to QikProp are available as well. See the function docstring or call
`qikprop_as_a_service.__doc__` to see the options.

The second object is the API Endpoint call wrapper `QikpropAsAService` which can be used to
integrate with exiting pipelines and make each of the API calls directly, without having to write the request itself
directly. This class only works on a per-call/file basis. The `qikprop_as_a_service` function uses this class to make
all of its calls and operations on each file. Its most common invocation is below (wrapped in a practical use), but
things such as the URI, endpoints, hashing functions, etc. can all be set in the class initialization.

```python
from qikpropservice import QikpropAsAService, QikPropOptions
from time import sleep

service = QikpropAsAService()

# Example of options, there are defaults for this model and it does not need to be passed to the Service calls
# if only defaults are wanted
options = QikPropOptions(fast=True, similar=30)

success, ret_code, data = service.post_task("file1.mol", options=options)
task_id = data["id"]
while True:
success, ret_code, ret_data = service.get_result(task_id=task_id, output_file="file1_result.tar.gz")
if success:
break
sleep(5)
```

See the documentation for each class and function to see its options and expected returns.

Utility
-------
There is an expected return code dataclass called `StatusCodes`. It's a simple holder for information regarding the
HTTP codes returned normally by the QikProp Service API Endpoint and what they mean.

The class is imported with
```python
from qikpropservice import StatusCodes

StatusCodes.ready # 200
StatusCodes.created # 201
StatusCodes.staged # 202
StatusCodes.error # 220
StatusCodes.null # 404
StatusCodes.unmatched # 409
```
where each of the attributes and codes corresponds to a particular meaning.

* ready : 200 - GET and POST
- Task is ready to pull down.
* created: 201 - POST
- Submitted task has been accepted by the server and no issues on input validation.
* staged: 202 - GET
- Task is queued in the service but has not been processed or is in processing.
* error : 220 - GET
- Task has been processed but had an error associated with processing. See data dict or pull error file for details.
* null : 404 - GET
- No task exists on the server with a given ID
* unmatched : 409 - GET and POST
- For a provided task ID and file data, Checksum/hashing does not match
20 changes: 20 additions & 0 deletions apiwrapper/qikpropservice/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# CLI tool:
# Call files, parse options
# Hash files
# Check Against database for existing hash
# Send file and get signal
# Pull completed files


# The file data hashed in the webapp are also hashable through:
# hashlib.sha1(f.read().encode('utf-8')).hexdigest()
# And yield the same result

from . import _version
__version__ = _version.get_versions()['version']

from .data_models import QikPropOptions, StatusCodes
from .qplib import qikprop_as_a_service, QikpropAsAService
from .qpcli import qpcli


Loading

0 comments on commit 8b1c6e1

Please sign in to comment.