Skip to content

Commit b1caff4

Browse files
authored
Merge pull request #5 from asapdiscovery/remove_OE_secret_shenannigans
Remove oe secret shenannigans and add basic CI
2 parents 3583f87 + 1a66d6f commit b1caff4

File tree

5 files changed

+167
-15
lines changed

5 files changed

+167
-15
lines changed

.github/workflows/CI.yaml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: CI
2+
3+
on:
4+
# GitHub has started calling new repo's first branch "main" https://github.com/github/renaming
5+
# The cookiecutter uses the "--initial-branch" flag when it runs git-init
6+
push:
7+
branches:
8+
- "main"
9+
pull_request:
10+
branches:
11+
- "main"
12+
schedule:
13+
# Weekly tests run on main by default:
14+
# Scheduled workflows run on the latest commit on the default or base branch.
15+
# (from https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule)
16+
- cron: "0 0 * * 0"
17+
18+
defaults:
19+
run:
20+
shell: bash -l {0}
21+
22+
23+
concurrency:
24+
group: "${{ github.workflow }}-${{ github.ref }}"
25+
cancel-in-progress: true
26+
27+
jobs:
28+
test:
29+
name: Test on ${{ matrix.os }}, Python ${{ matrix.python-version }}
30+
runs-on: ${{ matrix.os }}
31+
strategy:
32+
matrix:
33+
os: [macOS-latest, ubuntu-latest]
34+
python-version: ["3.10"]
35+
fail-fast: false
36+
37+
steps:
38+
- uses: actions/checkout@v3
39+
40+
- name: Additional info about the build
41+
shell: bash
42+
run: |
43+
uname -a
44+
df -h
45+
ulimit -a
46+
47+
# More info on options: https://github.com/marketplace/actions/provision-with-micromamba
48+
# More info on options: https://github.com/mamba-org/provision-with-micromamba
49+
- name: Setup Conda Environment
50+
uses: mamba-org/setup-micromamba@v1
51+
with:
52+
# default - will pull down 2.0 which we don't want!
53+
# micromamba-version: latest
54+
# pin to latest 1.x release
55+
micromamba-version: '1.5.10-0'
56+
environment-file: environment.yml
57+
environment-name: asap-ml-streamlit
58+
cache-environment: true
59+
cache-downloads: true
60+
cache-environment-key: environment-${{ steps.date.outputs.date }}
61+
cache-downloads-key: downloads-${{ steps.date.outputs.date }}
62+
create-args: >-
63+
python==${{ matrix.python-version }}
64+
65+
66+
# FIXME: Make the tests run
67+
# - name: Run tests
68+
# run: |
69+
# pytest -vvv --color=yes test_app.py
70+
71+

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@
55
oe_license.txt
66

77
# .env file
8-
.env
8+
.env
9+
10+
# __pycache__ folder
11+
__pycache__/

app.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def convert_df(df):
6767
input = st.selectbox(
6868
"How would you like to enter your input?",
6969
["Upload a CSV file", "Draw a molecule", "Enter SMILES", "Upload an SDF file"],
70+
key="input",
7071
)
7172

7273
multismiles = False
@@ -82,7 +83,7 @@ def convert_df(df):
8283
smiles_column_name = "SMILES"
8384
smiles_column = queried_df[smiles_column_name]
8485
elif input == "Enter SMILES":
85-
smiles = st.text_input("Enter a SMILES string")
86+
smiles = st.text_input("Enter a SMILES string", key="smiles_user_input")
8687
if _is_valid_smiles(smiles):
8788
st.success("Valid SMILES string", icon="✅")
8889
else:
@@ -95,7 +96,7 @@ def convert_df(df):
9596
elif input == "Upload a CSV file":
9697
# Create a file uploader for CSV files
9798
uploaded_file = st.file_uploader(
98-
"Choose a CSV file to upload your predictions to", type="csv"
99+
"Choose a CSV file to upload your predictions to", type="csv", key="csv_file"
99100
)
100101

101102
# If a file is uploaded, parse it into a DataFrame
@@ -104,7 +105,7 @@ def convert_df(df):
104105
else:
105106
st.stop()
106107
# Select a column from the DataFrame
107-
smiles_column_name = st.selectbox("Select a SMILES column", queried_df.columns)
108+
smiles_column_name = st.selectbox("Select a SMILES column", queried_df.columns, key="df_smiles_column")
108109
multismiles = True
109110
smiles_column = queried_df[smiles_column_name]
110111

@@ -128,15 +129,18 @@ def convert_df(df):
128129
# read with rdkit
129130
if uploaded_file is not None:
130131
# To convert to a string based IO:
131-
stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))
132-
# To read file as string:
133-
string_data = stringio.read()
134-
mols = sdf_str_to_rdkit_mol(string_data)
135-
smiles = [Chem.MolToSmiles(m) for m in mols]
136-
queried_df = pd.DataFrame(smiles, columns=["SMILES"])
137-
# st.error("Error reading the SDF file, please check the input", icon="🚨")
138-
# st.stop()
132+
try:
133+
stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))
134+
# To read file as string:
135+
string_data = stringio.read()
136+
mols = sdf_str_to_rdkit_mol(string_data)
137+
smiles = [Chem.MolToSmiles(m) for m in mols]
138+
queried_df = pd.DataFrame(smiles, columns=["SMILES"])
139+
except:
140+
st.error("Error reading the SDF file, please check the input", icon="🚨")
141+
st.stop()
139142
else:
143+
st.error("No file uploaded", icon="🚨")
140144
st.stop()
141145

142146
st.success(
@@ -154,11 +158,11 @@ def convert_df(df):
154158
# filter out None values
155159
targets = [t for t in targets if t is not None]
156160
# Select a target value from the preset list
157-
target_value = st.selectbox("Select a biological target ", targets)
161+
target_value = st.selectbox("Select a biological target ", targets, key="target")
158162
# endpoints
159163
endpoints = ASAPMLModelRegistry.get_endpoints()
160164
# Select a target value from the preset list
161-
endpoint_value = st.selectbox("Select a property ", endpoints)
165+
endpoint_value = st.selectbox("Select a property ", endpoints, key="endpoint")
162166

163167
if not ASAPMLModelRegistry.endpoint_has_target(endpoint_value):
164168
_target = None

environment.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
name: asap-ml-streamlit
2+
13
channels:
24
- conda-forge
35
- openeye
@@ -14,7 +16,6 @@ dependencies:
1416
- biopython
1517
- schedule
1618
- openeye-toolkits
17-
- asapdiscovery
1819

1920
# ml
2021
- pytorch
@@ -39,6 +40,8 @@ dependencies:
3940
- boto3
4041
- pandas
4142

43+
- pytest
44+
4245

4346

4447
# Pip-only installs

test_app.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import pytest
2+
import pandas as pd
3+
from streamlit.testing.v1 import AppTest
4+
5+
class STTester:
6+
timeout = 500
7+
8+
9+
@pytest.fixture()
10+
def app_path():
11+
# retirn
12+
return "./app.py"
13+
14+
@pytest.fixture()
15+
def smiles_dataframe_data():
16+
# synthetic data with multiple columns and SMILES
17+
data = {
18+
"mySmiles": ["CC", "CCC", "CCCC"],
19+
"blah": ["1", "2", "3"],
20+
"bleh": ["a", "b", "c"],
21+
}
22+
return pd.DataFrame(data)
23+
24+
@pytest.fixture()
25+
def smiles_dataframe_data_csv(tmp_path, smiles_dataframe_data):
26+
# synthetic data with multiple columns and SMILES
27+
csv_path = tmp_path / "smiles_data.csv"
28+
smiles_dataframe_data.to_csv(csv_path, index=False)
29+
return csv_path
30+
31+
32+
33+
class TestSMILES(STTester):
34+
35+
@pytest.mark.parametrize("target", ["SARS-CoV-2-Mpro", "MERS-CoV-Mpro"])
36+
@pytest.mark.parametrize("endpoint", ["pIC50", "LogD"])
37+
def test_smiles(self, app_path, endpoint, target, tmp_path):
38+
at = AppTest.from_file(app_path)
39+
at.run(timeout=self.timeout)
40+
at.selectbox(key="input").select("Enter SMILES").run(timeout=self.timeout)
41+
at.text_input(key="smiles_user_input").input("CC").run(timeout=self.timeout)
42+
at.selectbox(key="target").select(target).run(timeout=self.timeout)
43+
at.selectbox(key="endpoint").select(endpoint).run(timeout=self.timeout)
44+
val = at.markdown[-1].value # last markdown
45+
assert "CC" in val
46+
if not endpoint == "LogD":
47+
assert target in val
48+
else:
49+
assert "global" in val
50+
assert endpoint in val
51+
assert at.success
52+
53+
54+
55+
56+
class TestDataframe(STTester):
57+
58+
@pytest.mark.xfail(reason="No ability to mock file upload, see https://github.com/streamlit/streamlit/issues/8438")
59+
@pytest.mark.parametrize("target", ["SARS-CoV-2-Mpro", "MERS-CoV-Mpro"])
60+
@pytest.mark.parametrize("endpoint", ["pIC50", "LogD"])
61+
def test_dataframe(self, app_path, smiles_dataframe_data_csv, target, endpoint, tmp_path):
62+
at = AppTest.from_file(app_path)
63+
at.run(timeout=self.timeout)
64+
at.selectbox(key="input").select("Upload a CSV file").run(timeout=self.timeout)
65+
# cant be bother to mock testing internals to get this to work
66+
# you can also possibly use selenium to do this but seems like a lot of work
67+
at.file_uploader(key="csv_file").upload(smiles_dataframe_data).run(timeout=self.timeout)
68+
at.selectbox(key="df_smiles_column").select("mySmiles").run(timeout=self.timeout)
69+
at.selectbox(key="target").select("SARS-CoV-2-Mpro").run(timeout=self.timeout)
70+
at.selectbox(key="endpoint").select("pIC50").run(timeout=self.timeout)
71+
assert at.success

0 commit comments

Comments
 (0)