Skip to content

Commit

Permalink
Backend separation
Browse files Browse the repository at this point in the history
- extract, isolate and package it in a completely independent Python module, versioned and in a way that allows releases on PyPI.org
- fixed error in placeholder for secondary school (data registry defaults)
- added restriction in pytest version to install
- expected number of new cases fix
- data registry update (schema v2.1.1)
- github update
- deprecate ExpertApplication and CO2Application
- changes to reflect schema update 2.0.2
- version update
- Fixed error with f_inf (short-range)
  • Loading branch information
lrdossan committed Jul 15, 2024
1 parent bad998c commit e9868f9
Show file tree
Hide file tree
Showing 178 changed files with 1,447 additions and 785 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
env:
PROJECT_ROOT: ./
PROJECT_NAME: caimira
CAIMIRA_TESTS_CALCULATOR_TIMEOUT: 30
steps:
- name: Checkout
uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ sphinx:

python:
install:
- requirements: caimira/docs/requirements.txt
- requirements: caimira/docs/requirements.txt
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,25 +103,25 @@ pip install -e . # At the root of the repository
### Running the Calculator app in development mode

```
python -m caimira.apps.calculator
python -m ui.apps.calculator
```

To run with a specific template theme created:

```
python -m caimira.apps.calculator --theme=caimira/apps/templates/{theme}
python -m ui.apps.calculator --theme=ui/apps/templates/{theme}
```

To run the entire app in a different `APPLICATION_ROOT` path:

```
python -m caimira.apps.calculator --app_root=/myroot
python -m ui.apps.calculator --app_root=/myroot
```

To run the calculator on a different URL path:

```
python -m caimira.apps.calculator --prefix=/mycalc
python -m ui.apps.calculator --prefix=/mycalc
```

Each of these commands will start a local version of CAiMIRA, which can be visited at http://localhost:8080/.
Expand Down
2 changes: 1 addition & 1 deletion app-config/caimira-public-docker-image/run_caimira.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ nginx -c /opt/caimira/nginx.conf

cd /opt/caimira/src/caimira
# Run the calculator in the foreground.
/opt/caimira/app/bin/python -m caimira.apps.calculator --port 8081 --no-debug
/opt/caimira/app/bin/python -m ui.apps.calculator --port 8081 --no-debug
4 changes: 2 additions & 2 deletions app-config/calculator-app/app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ if [[ "$APP_NAME" == "calculator-app" ]]; then
export "DATA_SERVICE_ENABLED"="${DATA_SERVICE_ENABLED:=0}"
export "CAIMIRA_PROFILER_ENABLED"="${CAIMIRA_PROFILER_ENABLED:=0}"

echo "Starting the caimira webservice with: python -m caimira.apps.calculator ${args[@]}"
python -m caimira.apps.calculator "${args[@]}"
echo "Starting the caimira webservice with: python -m ui.apps.calculator ${args[@]}"
python -m ui.apps.calculator "${args[@]}"

else
echo "No APP_NAME specified"
Expand Down
3 changes: 1 addition & 2 deletions app-config/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
version: "3.8"
services:

calculator-app:
image: calculator-app
environment:
- COOKIE_SECRET
- APP_NAME=calculator-app
- APPLICATION_ROOT=/
- CAIMIRA_CALCULATOR_PREFIX=/calculator-cern
- CAIMIRA_THEME=caimira/apps/templates/cern
- CAIMIRA_THEME=ui/apps/templates/cern
- DATA_SERVICE_ENABLED=0
- CAIMIRA_PROFILER_ENABLED=0
user: ${CURRENT_UID}
Expand Down
1 change: 1 addition & 0 deletions app-config/openshift/deploymentconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,4 @@
- name: PROJECT_NAME
description: The name of this project, e.g. caimira-test
required: true

13 changes: 13 additions & 0 deletions caimira/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2020-2021 CERN. All rights not expressly granted are reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
File renamed without changes.
File renamed without changes.
31 changes: 31 additions & 0 deletions caimira/api/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# """
# Entry point for the CAiMIRA application
# """

import tornado.ioloop
import tornado.web
import tornado.log
from tornado.options import define, options
import logging

from caimira.api.routes.report_routes import ReportHandler

define("port", default=8088, help="Port to listen on", type=int)

logging.basicConfig(format="%(message)s", level=logging.INFO)

class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/report", ReportHandler),
]
settings = dict(
debug=True,
)
super(Application, self).__init__(handlers, **settings)

if __name__ == "__main__":
app = Application()
app.listen(options.port)
logging.info(f"Tornado server is running on port {options.port}")
tornado.ioloop.IOLoop.current().start()
File renamed without changes.
30 changes: 30 additions & 0 deletions caimira/api/controller/report_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import concurrent.futures
import functools

from caimira.calculator.validators.virus.virus_validator import VirusFormData
from caimira.calculator.store.data_registry import DataRegistry
import caimira.calculator.report.report_generator as rg


def generate_form_obj(form_data, data_registry):
return VirusFormData.from_dict(form_data, data_registry)


def generate_model(form_obj):
return form_obj.build_model(250_000)


def generate_report_results(form_obj, model):
return rg.calculate_report_data(form=form_obj, model=model, executor_factory=functools.partial(
concurrent.futures.ThreadPoolExecutor, None, # TODO define report_parallelism
),)


def submit_virus_form(form_data):
data_registry = DataRegistry

form_obj = generate_form_obj(form_data, data_registry)
model = generate_model(form_obj)
report_data = generate_report_results(form_obj, model=model)

return report_data
File renamed without changes.
28 changes: 28 additions & 0 deletions caimira/api/routes/report_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import json
import traceback
import tornado.web

from caimira.api.controller.report_controller import submit_virus_form

class ReportHandler(tornado.web.RequestHandler):
def set_default_headers(self):
self.set_header("Access-Control-Allow-Origin", "*")
self.set_header("Access-Control-Allow-Headers", "x-requested-with")
self.set_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")

def post(self):
try:
form_data = json.loads(self.request.body)
report_data = submit_virus_form(form_data)

response_data = {
"status": "success",
"message": "Results generated successfully",
"report_data": report_data,
}

self.write(response_data)
except Exception as e:
traceback.print_exc()
self.set_status(400)
self.write({"message": str(e)})
4 changes: 0 additions & 4 deletions caimira/apps/__init__.py

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ sphinx-rtd-theme==1.2.2
pillow==5.4.1
mock==1.0.1
commonmark==0.9.1
recommonmark==0.5.0
recommonmark==0.5.0
8 changes: 8 additions & 0 deletions caimira/calculator/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This module is part of CAiMIRA. Please see the repository at
# https://gitlab.cern.ch/caimira/caimira for details of the license and terms of use.
"""
Documentation for the CAiMIRA package
"""

__version__ = "1.0.0"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
from caimira import models
from caimira.data.weather import wx_data, nearest_wx_station
from caimira.calculator.models import models
from .weather import wx_data, nearest_wx_station

MONTH_NAMES = [
'January', 'February', 'March', 'April', 'May', 'June', 'July',
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion caimira/models.py → caimira/calculator/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import scipy.stats as sct
from scipy.optimize import minimize

from caimira.store.data_registry import DataRegistry
from caimira.calculator.store.data_registry import DataRegistry

if not typing.TYPE_CHECKING:
from memoization import cached
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
from scipy import special as sp
from scipy.stats import weibull_min

from caimira.enums import ViralLoads
from ..enums import ViralLoads

import caimira.monte_carlo.models as mc
from caimira.monte_carlo.sampleable import LogCustom, LogNormal, Normal, LogCustomKernel, CustomKernel, Uniform, Custom
from caimira.store.data_registry import DataRegistry
import caimira.calculator.models.monte_carlo.models as mc
from caimira.calculator.models.monte_carlo.sampleable import LogCustom, LogNormal, Normal, LogCustomKernel, CustomKernel, Uniform, Custom
from caimira.calculator.store.data_registry import DataRegistry


def evaluate_vl(root: typing.Dict, value: str, data_registry: DataRegistry):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys
import typing

import caimira.models
from caimira.calculator.models import models

from .sampleable import SampleableDistribution, _VectorisedFloatOrSampleable

Expand Down Expand Up @@ -57,38 +57,38 @@ def _build_mc_model(model: dataclass_instance) -> typing.Type[MCModelBase[_Model
# Note: deepcopy not needed here as we aren't mutating entities beyond
# the top level.
new_field = copy.copy(field)
if field.type is caimira.models._VectorisedFloat: # noqa
if field.type is models._VectorisedFloat: # noqa
new_field.type = _VectorisedFloatOrSampleable # type: ignore

field_type: typing.Any = new_field.type

if getattr(field_type, '__origin__', None) in [typing.Union, typing.Tuple]:
# It is challenging to generalise this code, so we provide specific transformations,
# and raise for unforseen cases.
if new_field.type == typing.Tuple[caimira.models._VentilationBase, ...]:
if new_field.type == typing.Tuple[models._VentilationBase, ...]:
VB = getattr(sys.modules[__name__], "_VentilationBase")
field_type = typing.Tuple[typing.Union[caimira.models._VentilationBase, VB], ...]
elif new_field.type == typing.Tuple[caimira.models._ExpirationBase, ...]:
field_type = typing.Tuple[typing.Union[models._VentilationBase, VB], ...]
elif new_field.type == typing.Tuple[models._ExpirationBase, ...]:
EB = getattr(sys.modules[__name__], "_ExpirationBase")
field_type = typing.Tuple[typing.Union[caimira.models._ExpirationBase, EB], ...]
elif new_field.type == typing.Tuple[caimira.models.SpecificInterval, ...]:
field_type = typing.Tuple[typing.Union[models._ExpirationBase, EB], ...]
elif new_field.type == typing.Tuple[models.SpecificInterval, ...]:
SI = getattr(sys.modules[__name__], "SpecificInterval")
field_type = typing.Tuple[typing.Union[caimira.models.SpecificInterval, SI], ...]
field_type = typing.Tuple[typing.Union[models.SpecificInterval, SI], ...]

elif new_field.type == typing.Union[int, caimira.models.IntPiecewiseConstant]:
elif new_field.type == typing.Union[int, models.IntPiecewiseConstant]:
IPC = getattr(sys.modules[__name__], "IntPiecewiseConstant")
field_type = typing.Union[int, caimira.models.IntPiecewiseConstant, IPC]
elif new_field.type == typing.Union[caimira.models.Interval, None]:
field_type = typing.Union[int, models.IntPiecewiseConstant, IPC]
elif new_field.type == typing.Union[models.Interval, None]:
I = getattr(sys.modules[__name__], "Interval")
field_type = typing.Union[None, caimira.models.Interval, I]
field_type = typing.Union[None, models.Interval, I]

else:
# Check that we don't need to do anything with this type.
for item in new_field.type.__args__:
if getattr(item, '__module__', None) == 'caimira.models':
if getattr(item, '__module__', None) == 'source.models.models':
raise ValueError(
f"unsupported type annotation transformation required for {new_field.type}")
elif field_type.__module__ == 'caimira.models':
elif field_type.__module__ == 'source.models.models':
mc_model = getattr(sys.modules[__name__], new_field.type.__name__)
field_type = typing.Union[new_field.type, mc_model]

Expand Down Expand Up @@ -119,7 +119,7 @@ def _build_mc_model(model: dataclass_instance) -> typing.Type[MCModelBase[_Model


_MODEL_CLASSES = [
cls for cls in vars(caimira.models).values()
cls for cls in vars(models).values()
if dataclasses.is_dataclass(cls)
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy as np
from sklearn.neighbors import KernelDensity # type: ignore

import caimira.models
from caimira.calculator.models import models

# Declare a float array type of a given size.
# There is no better way to declare this currently, unfortunately.
Expand Down Expand Up @@ -158,5 +158,5 @@ def generate_samples(self, size: int) -> float_array_size_n:


_VectorisedFloatOrSampleable = typing.Union[
SampleableDistribution, caimira.models._VectorisedFloat,
SampleableDistribution, models._VectorisedFloat,
]
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit e9868f9

Please sign in to comment.