Skip to content

Commit 41f50b7

Browse files
committed
fix: moved HOSE code endpoint to chem router and various other reorganisational changes
1 parent 17aef10 commit 41f50b7

File tree

3 files changed

+176
-141
lines changed

3 files changed

+176
-141
lines changed

app/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from fastapi.responses import RedirectResponse
44
from fastapi_versioning import VersionedFastAPI
55

6+
from .routers import registration
67
from .routers import chem
78
from fastapi.middleware.cors import CORSMiddleware
89

@@ -26,6 +27,7 @@
2627
},
2728
)
2829

30+
app.include_router(registration.router)
2931
app.include_router(chem.router)
3032

3133
app.add_event_handler("startup", tasks.create_start_app_handler(app))

app/routers/chem.py

Lines changed: 3 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
1-
from typing import List, Annotated, Union
2-
from app.core.config import LWREG_CONFIG
1+
from typing import Annotated
32
from psycopg2.errors import UniqueViolation
43
from app.modules.cdkmodules import getCDKHOSECodes
5-
from fastapi import APIRouter, HTTPException, Body, status, Query
4+
from fastapi import APIRouter, HTTPException, status, Query
65
from app.modules.rdkitmodules import getRDKitHOSECodes
7-
from lwreg.utils import (
8-
initdb,
9-
bulk_register,
10-
query,
11-
retrieve,
12-
RegistrationFailureReasons,
13-
)
14-
from rdkit import Chem
15-
from io import BytesIO
166
from app.schemas import HealthCheck
177

188
router = APIRouter(
@@ -46,137 +36,9 @@ def get_health() -> HealthCheck:
4636
return HealthCheck(status="OK")
4737

4838

49-
@router.post(
50-
"/init",
51-
tags=["chem"],
52-
summary="Initializes the registration database",
53-
response_description="Returns boolean indicating the success of the initialisation",
54-
status_code=status.HTTP_200_OK,
55-
response_model=Union[bool, None],
56-
)
57-
async def initialise_database(confirm: Annotated[bool, Body(embed=True)] = False):
58-
"""
59-
## Initializes the registration database
60-
61-
NOTE: This call destroys any existing information in the registration database
62-
63-
Arguments:
64-
65-
confirm -- if set to False we immediately return
66-
"""
67-
return initdb(config=LWREG_CONFIG, confirm=confirm)
68-
69-
70-
@router.post(
71-
"/register",
72-
tags=["chem"],
73-
summary="Registers new molecules",
74-
response_description="Returns the new registry number(s) (molregno). If all entries are duplicates exception is raised",
75-
status_code=status.HTTP_200_OK,
76-
response_model=List[str | int],
77-
)
78-
async def register_compounds(
79-
data: Annotated[
80-
str,
81-
Body(embed=False, media_type="text/plain"),
82-
] = "CCCC"
83-
):
84-
"""
85-
## Registers new molecules, assuming it doesn't already exist,
86-
and returns the new registry number(s) (molregno). If all entries
87-
are duplicates exception is raised
88-
89-
#### Only one of the molecule format objects should be provided
90-
91-
molblock -- MOL or SDF block
92-
smiles -- smiles
93-
"""
94-
try:
95-
if "$$$$" in data:
96-
molStream = BytesIO(data.encode("utf8"))
97-
mols = [m for m in Chem.ForwardSDMolSupplier(molStream)]
98-
else:
99-
smiles = data.splitlines()
100-
mols = [Chem.MolFromSmiles(smi) for smi in smiles]
101-
if len(mols) > 0:
102-
db_responses = bulk_register(mols=mols, config=LWREG_CONFIG)
103-
reg_responses = []
104-
ops_total_failure = True
105-
for res in db_responses:
106-
if res == RegistrationFailureReasons.PARSE_FAILURE:
107-
reg_responses.append("PARSE_FAILURE")
108-
elif res == RegistrationFailureReasons.DUPLICATE:
109-
reg_responses.append("DUPLICATE")
110-
else:
111-
ops_total_failure = False
112-
reg_responses.append(res)
113-
if ops_total_failure:
114-
raise
115-
else:
116-
return reg_responses
117-
else:
118-
raise
119-
except Exception as e:
120-
raise HTTPException(
121-
status_code=422,
122-
detail="Registration failed: ALL_DUPLICATE_ENTRIES " + e.message,
123-
)
124-
125-
126-
@router.get(
127-
"/query",
128-
tags=["chem"],
129-
summary="Queries to see if a molecule has already been registered",
130-
response_model=List[int],
131-
response_description="Returns the corresponding registry numbers (molregnos)",
132-
status_code=status.HTTP_200_OK,
133-
)
134-
async def query_compounds(smi: str):
135-
"""
136-
## Queries to see if a molecule has already been registered
137-
138-
Returns:
139-
Corresponding registry numbers (molregnos)
140-
"""
141-
try:
142-
res = query(smiles=smi, config=LWREG_CONFIG)
143-
return res
144-
except Exception as e:
145-
raise HTTPException(
146-
status_code=500,
147-
detail="Internal Server Error" + e.message,
148-
)
149-
150-
151-
@router.post(
152-
"/retrieve",
153-
tags=["chem"],
154-
summary="Retrieves entries based on the list of ids provided",
155-
response_model=tuple(),
156-
response_description="Returns HTTP Status Code 200 (OK)",
157-
status_code=status.HTTP_200_OK,
158-
)
159-
async def retrieve_compounds(ids: List[int]):
160-
"""
161-
## Retrieves entries based on the ids provided
162-
163-
Returns:
164-
Molecule data for one or more registry ids (molregnos).
165-
The return value is a tuple of (molregno, data, format) 3-tuples
166-
"""
167-
try:
168-
res = retrieve(ids=ids, config=LWREG_CONFIG)
169-
return res
170-
except Exception as e:
171-
raise HTTPException(
172-
status_code=500,
173-
detail="Internal Server Error" + e.message,
174-
)
175-
176-
17739
@router.get(
17840
"/hosecode",
179-
tags=["chem"],
41+
tags=["registration"],
18042
summary="Generates HOSE codes of molecule",
18143
response_model=list[str],
18244
response_description="Returns an array of hose codes generated",

app/routers/registration.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
from typing import List, Annotated, Union
2+
from app.core.config import LWREG_CONFIG
3+
from fastapi import APIRouter, HTTPException, Body, status
4+
from lwreg.utils import (
5+
initdb,
6+
bulk_register,
7+
query,
8+
retrieve,
9+
RegistrationFailureReasons,
10+
)
11+
from rdkit import Chem
12+
from io import BytesIO
13+
from app.schemas import HealthCheck
14+
15+
router = APIRouter(
16+
prefix="/registration",
17+
tags=["registration"],
18+
dependencies=[],
19+
responses={404: {"description": "Not found"}},
20+
)
21+
22+
23+
@router.get("/", include_in_schema=False)
24+
@router.get(
25+
"/health",
26+
tags=["healthcheck"],
27+
summary="Perform a Health Check on Registration Module",
28+
response_description="Return HTTP Status Code 200 (OK)",
29+
status_code=status.HTTP_200_OK,
30+
include_in_schema=False,
31+
response_model=HealthCheck,
32+
)
33+
def get_health() -> HealthCheck:
34+
"""
35+
## Perform a Health Check
36+
Endpoint to perform a healthcheck on. This endpoint can primarily be used Docker
37+
to ensure a robust container orchestration and management is in place. Other
38+
services which rely on proper functioning of the API service will not deploy if this
39+
endpoint returns any other HTTP status code except 200 (OK).
40+
Returns:
41+
HealthCheck: Returns a JSON response with the health status
42+
"""
43+
return HealthCheck(status="OK")
44+
45+
46+
@router.post(
47+
"/init",
48+
tags=["registration"],
49+
summary="Initializes the registration database",
50+
response_description="Returns boolean indicating the success of the initialisation",
51+
status_code=status.HTTP_200_OK,
52+
response_model=Union[bool, None],
53+
)
54+
async def initialise_database(confirm: Annotated[bool, Body(embed=True)] = False):
55+
"""
56+
## Initializes the registration database
57+
58+
NOTE: This call destroys any existing information in the registration database
59+
60+
Arguments:
61+
62+
confirm -- if set to False we immediately return
63+
"""
64+
return initdb(config=LWREG_CONFIG, confirm=confirm)
65+
66+
67+
@router.post(
68+
"/register",
69+
tags=["registration"],
70+
summary="Registers new molecules",
71+
response_description="Returns the new registry number(s) (molregno). If all entries are duplicates exception is raised",
72+
status_code=status.HTTP_200_OK,
73+
response_model=List[str | int],
74+
)
75+
async def register_compounds(
76+
data: Annotated[
77+
str,
78+
Body(embed=False, media_type="text/plain"),
79+
] = "CCCC"
80+
):
81+
"""
82+
## Registers new molecules, assuming it doesn't already exist,
83+
and returns the new registry number(s) (molregno). If all entries
84+
are duplicates exception is raised
85+
86+
#### Only one of the molecule format objects should be provided
87+
88+
molblock -- MOL or SDF block
89+
smiles -- smiles
90+
"""
91+
try:
92+
if "$$$$" in data:
93+
molStream = BytesIO(data.encode("utf8"))
94+
mols = [m for m in Chem.ForwardSDMolSupplier(molStream)]
95+
else:
96+
smiles = data.splitlines()
97+
mols = [Chem.MolFromSmiles(smi) for smi in smiles]
98+
if len(mols) > 0:
99+
db_responses = bulk_register(mols=mols, config=LWREG_CONFIG)
100+
reg_responses = []
101+
ops_total_failure = True
102+
for res in db_responses:
103+
if res == RegistrationFailureReasons.PARSE_FAILURE:
104+
reg_responses.append("PARSE_FAILURE")
105+
elif res == RegistrationFailureReasons.DUPLICATE:
106+
reg_responses.append("DUPLICATE")
107+
else:
108+
ops_total_failure = False
109+
reg_responses.append(res)
110+
if ops_total_failure:
111+
raise
112+
else:
113+
return reg_responses
114+
else:
115+
raise
116+
except Exception as e:
117+
raise HTTPException(
118+
status_code=422,
119+
detail="Registration failed: ALL_DUPLICATE_ENTRIES " + e.message,
120+
)
121+
122+
123+
@router.get(
124+
"/query",
125+
tags=["registration"],
126+
summary="Queries to see if a molecule has already been registered",
127+
response_model=List[int],
128+
response_description="Returns the corresponding registry numbers (molregnos)",
129+
status_code=status.HTTP_200_OK,
130+
)
131+
async def query_compounds(smi: str):
132+
"""
133+
## Queries to see if a molecule has already been registered
134+
135+
Returns:
136+
Corresponding registry numbers (molregnos)
137+
"""
138+
try:
139+
res = query(smiles=smi, config=LWREG_CONFIG)
140+
return res
141+
except Exception as e:
142+
raise HTTPException(
143+
status_code=500,
144+
detail="Internal Server Error" + e.message,
145+
)
146+
147+
148+
@router.post(
149+
"/retrieve",
150+
tags=["registration"],
151+
summary="Retrieves entries based on the list of ids provided",
152+
response_model=tuple(),
153+
response_description="Returns HTTP Status Code 200 (OK)",
154+
status_code=status.HTTP_200_OK,
155+
)
156+
async def retrieve_compounds(ids: List[int]):
157+
"""
158+
## Retrieves entries based on the ids provided
159+
160+
Returns:
161+
Molecule data for one or more registry ids (molregnos).
162+
The return value is a tuple of (molregno, data, format) 3-tuples
163+
"""
164+
try:
165+
res = retrieve(ids=ids, config=LWREG_CONFIG)
166+
return res
167+
except Exception as e:
168+
raise HTTPException(
169+
status_code=500,
170+
detail="Internal Server Error" + e.message,
171+
)

0 commit comments

Comments
 (0)