Skip to content

Commit

Permalink
Merge pull request #20 from fenfisdi/issue/9/insert_cmodels_in_database
Browse files Browse the repository at this point in the history
Issue/9/insert cmodels in database

This PR was initially opened to address issue #9. However The issue was indirectly related to these other issues that will also be closed. 

closes #9
closes #23
closes #10
closes #21
  • Loading branch information
jearistiz authored Apr 25, 2021
2 parents b902207 + 930fbdb commit 6d54fe3
Show file tree
Hide file tree
Showing 34 changed files with 818 additions and 217 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,6 @@ cython_debug/

# Experiments
experiments/

# MacOS
.DS_Store
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM python:3.8-slim-buster
EXPOSE 8080

ENV PYTHONUNBUFFERED 1
ENV APP_HOME /app

COPY requirements.txt .

RUN pip install --no-cache-dir -U pip \
&& pip install --no-cache-dir -r requirements.txt

WORKDIR ${APP_HOME}

COPY src src
COPY main.py .
COPY docker-entrypoint.sh .
COPY .env .

ENTRYPOINT ["/bin/bash"]
CMD ["./docker-entrypoint.sh"]
2 changes: 1 addition & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
version: "3.5"
services:
user_app:
build: .
container_name: cdslab_models_app
env_file: .env
image: cdslab_user
networks:
- cdslab_models
ports:
- 5000:5000
volumes:
- ./src:/app/src

user_mongo:
container_name: cdslab_models_mongo
environment:
MONGO_INITDB_ROOT_USERNAME: cdsuser
MONGO_INITDB_ROOT_PASSWORD: cdspass
image: mongo:3-xenial
networks:
- cdslab_models
ports:
- 27017:27017
volumes:
- /tmp/data/cdslab_models/:/data/db


networks:
cdslab_models:
name: cdslab_user
driver: bridge
7 changes: 7 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

if [ -z "${PORT}" ] ; then PORT=8080; fi

if [ -z "${HOST}" ] ; then HOST=0.0.0.0; fi

uvicorn main:app --port=${PORT} --host=${HOST} --reload
11 changes: 9 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
from src.db.mongo import MongoClientSingleton
import uvicorn

from src.api import app
from src.config import settings
from src.use_cases.cmodels import CmodelUseCases

if __name__ == '__main__':
__all__ = ['app']

if __name__ == '__main__':
mongo_singleton = MongoClientSingleton()
CmodelUseCases(mongo_singleton).update_cmodels_collection()
uvicorn.run(
"src.api:app",
host=settings['HOST'],
host=settings.get('HOST'),
port=int(settings['PORT']),
reload=True,
debug=True,
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ iniconfig==1.1.1
mccabe==0.6.1
mongomock==3.22.1
packaging==20.9; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
pandas==1.2.4
pluggy==0.13.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
py==1.10.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
pycodestyle==2.7.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
Expand All @@ -33,6 +34,7 @@ pyparsing==2.4.7; python_version >= '2.6' and python_version not in '3.0, 3.1, 3
pytest-cov==2.11.1
pytest==6.2.3
python-dotenv==0.17.0
python-multipart==0.0.5
requests==2.25.1
sentinels==1.0.0
six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
Expand Down
9 changes: 4 additions & 5 deletions src/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@

app = FastAPI()


app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=settings["ALLOWED_HOSTS"].split(",")
allowed_hosts=settings.get("ALLOWED_HOSTS", "*").split(",")
)

app.add_middleware(
CORSMiddleware,
allow_credentials=True,
allow_origins=settings["ALLOWED_ORIGINS"].split(","),
allow_methods=settings["ALLOWED_METHODS"].split(","),
allow_headers=settings["ALLOWED_HEADERS"].split(",")
allow_origins=settings.get("ALLOWED_ORIGINS", "*").split(","),
allow_methods=settings.get("ALLOWED_METHODS", "*").split(","),
allow_headers=settings.get("ALLOWED_HEADERS", "*").split(",")
)

app.include_router(
Expand Down
4 changes: 2 additions & 2 deletions src/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dotenv import dotenv_values


settings = dotenv_values(".env")
db_config = dotenv_values(".db_config")
settings = dotenv_values('.env')
db_config = dotenv_values('.db_config')
122 changes: 81 additions & 41 deletions src/db/mongo.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,87 @@
from typing import Generator, Tuple
from typing import Generator, Optional, Tuple, Union

from pymongo import MongoClient
from pymongo.collection import Collection
from pymongo.database import Database
import mongomock

from src.config import db_config
from src.utils.patterns import Singleton


class MongoClientSingleton(metaclass=Singleton):
db_uri: Optional[str] = db_config.get('MONGO_URI'),

def __init__(
self,
db_connection: MongoClient = MongoClient(db_uri),
db: Union[str, Database] = db_config.get('MONGO_DB'),
coll: Union[str, Collection] = db_config.get('CMODELS_COLL')
) -> None:
self.db_connection = db_connection
self.db = db
self.coll = coll

def api_get_db_connection(self) -> Generator[MongoClient, None, None]:
"""Creates connection to Mongodb server.
Yields
------
db_connection: MongoClient
Object containing the db connection.
"""
try:
yield self.db_connection
finally:
self.db_connection.close()

def get_db(
self,
db: Optional[str] = None
) -> Tuple[MongoClient, Database]:
"""Gets Mongodb connection and database.
Returns
-------
db_connection : MongoClient
db : pymongo.database.Database
"""
if db and isinstance(db, str):
self.db = db
return self.db_connection, self.db

def get_collection(
self,
coll: Optional[str] = None
) -> Tuple[MongoClient, Collection]:
"""
Returns
-------
db_connection: pymongo.MongoClient
coll: pymongo.collection.Collection
"""
if coll and isinstance(coll, str):
self.coll = coll
return self.db_connection, self.coll

@property
def db(self):
return self._db

@db.setter
def db(self, value): # noqa
if isinstance(value, str):
self._db = self.db_connection[value]
elif isinstance(value, Database) or isinstance(value, mongomock.Database):
self._db = value

@property
def coll(self):
return self._coll

def api_get_db_connection(
db_uri: str = db_config['MONGO_URI'],
) -> Generator[MongoClient, None, None]:
"""Creates connection to Mongodb server.
Yields
------
db_connection: MongoClient
Object containing the db connection.
"""
db_connection = MongoClient(db_uri)

try:
yield db_connection
finally:
db_connection.close()


def get_db(
db_uri: str = db_config['MONGO_URI'],
db_name: str = db_config['MONGO_DB']
) -> Tuple[MongoClient, Database]:
"""Gets Mongodb connection and database.
Parameters
----------
db_uri: str
Mongo server URI.
db_name: str
Mongo database name.
Returns
-------
db_connection : MongoClient
db : pymongo.database.Database
"""
db_connection = MongoClient(db_uri)
db: Database = db_connection[db_name]

return db_connection, db
@coll.setter
def coll(self, value): # noqa
if isinstance(value, str):
self._coll = self.db[value]
elif isinstance(value, Collection) or isinstance(value, mongomock.Collection):
self._coll = value
5 changes: 0 additions & 5 deletions src/interfaces/cmodel_interface.py

This file was deleted.

60 changes: 60 additions & 0 deletions src/interfaces/cmodels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from datetime import datetime

from src.db.mongo import MongoClientSingleton
from src.models.db.cmodels import (
CompartmentalModel,
CompartmentalModelEnum
)
from src.interfaces.crud import MongoCRUD


class CModelsInterface:

def __init__(
self,
mongo_singleton: MongoClientSingleton
) -> None:
self.mongo_singleton = mongo_singleton
self.crud = MongoCRUD(self.mongo_singleton)

def insert_one_cmodel_document(self, model: CompartmentalModel):

cmodel_document = model.dict(by_alias=True)

existent_model = self.crud.read(model.id)

if existent_model:
pruned_existent_model = CModelsInterface._prune_db_document(
existent_model
)
pruned_current_model = CModelsInterface._prune_db_document(
cmodel_document
)
if pruned_existent_model == pruned_current_model:
# TODO: log cmodel exists f'Cmodel exists: {model.name}'
return existent_model
else:
model.updated_at = datetime.utcnow()
updated_model = self.crud.update(
model.id,
model.dict(by_alias=True)
)
# TODO log updated cmodel f'Updated cmodel: {model.name}'
return updated_model
else:
model_inserted = self.crud.insert(cmodel_document)
# TODO: log created cmodel f'Created cmodel: {model.name}'
return model_inserted

def insert_all_cmodel_documents(self):
return [
self.insert_one_cmodel_document(model)
for model in CompartmentalModelEnum.values()
]

@staticmethod
def _prune_db_document(model_in_db: dict) -> dict:
if model_in_db:
model_in_db.pop('inserted_at')
model_in_db.pop('updated_at')
return model_in_db
Loading

0 comments on commit 6d54fe3

Please sign in to comment.