-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.py
189 lines (156 loc) · 6.54 KB
/
config.py
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import os
# File is responsible for defining globals and initializing them
try:
from mongo_connection import MongoConnection
except ImportError:
from .mongo_connection import MongoConnection
from bson.objectid import ObjectId
MONGO_CONNECTION = MongoConnection()
def init(study_id, study_file_id, user_metric_uuid=None, action=None):
global __metric_properties
study = Study(study_id)
study_file = StudyFile(study_file_id)
__metric_properties = MetricProperties(study, study_file, user_metric_uuid, action)
def set_parent_event_name(event_name):
global __event_name
__event_name = event_name
def get_parent_event_name():
global __event_name
return __event_name
def get_metric_properties():
global __metric_properties
return __metric_properties
class MetricProperties:
"""Sets default properties for Mixpanel events"""
# This is a generic write-only log token, not a secret
USER_ID = "2f30ec50-a04d-4d43-8fd1-b136a2045079"
def __init__(self, study, study_file, user_uuid=None, action=None):
distinct_id = user_uuid if user_uuid else MetricProperties.USER_ID
self.__properties = {
"distinct_id": distinct_id,
"studyAccession": study.accession,
"fileName": study_file.file_name,
"fileType": study_file.file_type,
"fileSize": study_file.file_size,
"trigger": study_file.trigger,
"logger": "ingest-pipeline",
"appId": "single-cell-portal",
"action": action
}
# merge in referenceAnnDataFile if necessary
if study_file.file_type == 'AnnData':
self.__properties["referenceAnnDataFile"] = study_file.is_reference_anndata
def get_properties(self):
return self.__properties
def update(self, props):
if props:
self.__properties = {**self.__properties, **props}
self.set_mixpanel_nums()
def set_mixpanel_nums(self):
"""Derive count for each type of Mixpanel property"""
for prop in ["errorTypes", "errors", "warningTypes", "warnings"]:
num_prop = "num" + prop[0].upper() + prop[1:]
if self.__properties.get(prop):
self.__properties[num_prop] = len(self.__properties[prop])
def append_issue(self, props):
"""Add error/warning properties to MetricsProperties
without clobbering
"""
if props:
updated_props = {}
for prop in ["errorTypes", "errors", "warningTypes", "warnings"]:
if prop in self.__properties:
updated_props.setdefault(prop, []).extend(self.__properties[prop])
if prop in props:
updated_props.setdefault(prop, []).extend(props[prop])
for key in updated_props.keys():
if key in ["errorTypes", "warningTypes"]:
self.__properties[key] = list(set(updated_props[key]))
else:
self.__properties[key] = updated_props[key]
self.set_mixpanel_nums()
def bypass_mongo_writes():
"""Check if developer has set environment variable to bypass writing data to MongoDB
BYPASS_MONGO_WRITES='yes'
"""
if os.environ.get("BYPASS_MONGO_WRITES") is not None:
skip = os.environ["BYPASS_MONGO_WRITES"]
if skip == "yes":
return True
else:
return False
else:
return False
class Study:
"""Provides attributes for a given study"""
def __init__(self, study_id):
self.study = study_id
@property
def study(self):
return self.__study
@study.setter
def study(self, study_id: str):
# Annotation Object expects a proper BSON ID
# even when the input validation is bypassed here
try:
study_id = ObjectId(study_id)
except Exception:
raise ValueError("Must pass in valid object ID for study ID.")
# set dummy accession if running in developer mode
if bypass_mongo_writes():
self.accession = "SCPdev"
else:
study = list(
MONGO_CONNECTION._client["study_accessions"].find(
{"study_id": study_id}, {"_id": 0}
)
)
if not study:
raise ValueError(
"Study ID is not registered with a study. Please provide a valid study ID."
)
else:
self.__study = study.pop()
self.accession = self.__study["accession"]
class StudyFile:
"Provides attributes for a given study file"
def __init__(self, study_file_id):
self.study_file = study_file_id
@property
def study_file(self):
return self.__study_file
@study_file.setter
def study_file(self, study_file_id):
try:
study_file_id = ObjectId(study_file_id)
except Exception:
raise ValueError("Must pass in valid object ID for study file ID.")
if bypass_mongo_writes():
# set dummy values if running in developer mode
self.file_type = "input_validation_bypassed"
self.file_size = 1
self.file_name = str(study_file_id)
self.trigger = 'dev-mode'
else:
query = MONGO_CONNECTION._client["study_files"].find({"_id": study_file_id})
query_results = list(query)
if not query_results:
raise ValueError(
"Study file ID is not registered with a study. Please provide a valid study file ID."
)
else:
self.__study_file = query_results.pop()
self.file_type = self.study_file["file_type"]
self.file_size = self.study_file["upload_file_size"]
self.file_name = self.study_file["name"]
upload_trigger = self.study_file.get("options", {}).get("upload_trigger")
# when set, remote_location is the name of the file in the bucket
if upload_trigger is not None:
self.trigger = upload_trigger
elif self.study_file["remote_location"] is not None:
self.trigger = 'upload' if self.study_file["remote_location"] == "" else 'sync'
# indicate trigger state for tests/mocks
else:
self.trigger = 'not set'
if self.study_file["file_type"] == 'AnnData':
self.is_reference_anndata = self.study_file.get("ann_data_file_info", {}).get("reference_file")