-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy path__init__.py
More file actions
127 lines (115 loc) · 4.54 KB
/
__init__.py
File metadata and controls
127 lines (115 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import azure.functions as func
from cdisc_rules_engine.services.cache.in_memory_cache_service import (
InMemoryCacheService,
)
from cdisc_rules_engine.utilities.utils import normalize_adam_input
from cdisc_rules_engine.services.cdisc_library_service import CDISCLibraryService
from cdisc_rules_engine.services.cache.cache_populator_service import CachePopulator
from scripts.run_validation import run_single_rule_validation
import json
import os
import asyncio
import numpy as np
import traceback
class BadRequestError(Exception):
pass
def validate_datasets_payload(datasets):
required_keys = {"filename", "label", "domain", "records", "variables"}
missing_keys = set()
for dataset in datasets:
for key in required_keys:
if key not in dataset:
missing_keys.add(key)
for var in dataset.get("variables", []):
if var is None:
raise BadRequestError(
f"Dataset: {dataset.get('label')} is missing variable metadata"
)
if missing_keys:
raise KeyError(
f"one or more datasets missing the following keys {missing_keys}"
)
def handle_exception(e: Exception):
if isinstance(e, KeyError):
return func.HttpResponse(
json.dumps({"error": "KeyError", "message": str(e)}), status_code=400
)
elif isinstance(e, BadRequestError):
return func.HttpResponse(
json.dumps({"error": "BadRequestError", "message": str(e)}), status_code=400
)
else:
return func.HttpResponse(
json.dumps(
{
"error": "Unknown Exception",
"message": f"An unhandled exception occurred. {str(e)}",
"traceback": traceback.format_exc(),
}
),
status_code=400,
)
def convert_numpy_types(obj):
"""Recursively convert numpy types to native Python types"""
if isinstance(obj, dict):
return {key: convert_numpy_types(value) for key, value in obj.items()}
elif isinstance(obj, list):
return [convert_numpy_types(item) for item in obj]
elif isinstance(obj, (np.integer, np.int64, np.int32, np.int16, np.int8)):
return int(obj)
elif isinstance(obj, (np.floating, np.float64, np.float32, np.float16)):
return float(obj)
elif isinstance(obj, np.bool_):
return bool(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
elif hasattr(obj, "item"):
return obj.item()
else:
return obj
def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: # noqa
try:
json_data = req.get_json()
api_key = os.environ.get("CDISC_LIBRARY_API_KEY", "") # Default to empty string
api_url = os.environ.get("CDISC_LIBRARY_API_URL", "") # Default to empty string
rule = json_data.get("rule")
standards_data = json_data.get("standard", {})
standard = standards_data.get("product")
standard_version = standards_data.get("version")
standard_substandard = standards_data.get("substandard")
standard, standard_version = normalize_adam_input(standard, standard_version)
codelists = json_data.get("codelists", [])
cache = InMemoryCacheService()
library_service = CDISCLibraryService(api_key, api_url, cache)
cache_populator: CachePopulator = CachePopulator(cache, library_service)
asyncio.run(cache_populator.load_available_ct_packages())
if standards_data or codelists:
if standards_data:
asyncio.run(
cache_populator.load_standard(
standard, standard_version, standard_substandard
)
)
asyncio.run(cache_populator.load_codelists(codelists))
if not rule:
raise KeyError("'rule' required in request")
datasets = json_data.get("datasets")
if not datasets:
raise KeyError("'datasets' required in request")
validate_datasets_payload(datasets)
define_xml = json_data.get("define_xml")
result = run_single_rule_validation(
datasets,
rule,
define_xml,
cache,
standard,
standard_version,
standard_substandard,
codelists,
)
result = convert_numpy_types(result)
result_json = json.dumps(result)
return func.HttpResponse(result_json)
except Exception as e:
return handle_exception(e)