11'''
22TODO
3- maybe there should be a way to check if a project has an existing ontology, and that it would overwrite it?
3+ Option.add_option() currently creates a new Classification object. however, this does not work for certain Classification options.
4+ Example:
5+ Classification.Type.DROPDOWN -> the options for this class_type should only generate more nested dropdowns
6+ -> Dropdowns are supposed to be removed moving forward, but this is a current problem
7+ -> This is the most major issue because going to the doubly nested class will break the UI
8+ Classification.Type.CHECKLIST & Classification.Type.TEXT-> the option cannot have a nested Classification.
9+ -> this reflects accurately in the UI without issues, but when you query via graphql, it shows what was input
10+ -> this is a lesser issue because the UI will not reflect the unavailable fields
11+ Is there an effective way to enforce limitations on Option.add_option()?
12+ -> Maybe a way to check if the Option itself has options when adding it to a Classification?
413'''
514
615from dataclasses import dataclass , field
1423class InconsistentOntologyException (Exception ):
1524 pass
1625
17- class Classification :
18- pass
19-
2026@dataclass
2127class Option :
2228 value : str
2329 schema_id : Optional [str ] = None
2430 feature_schema_id : Optional [str ] = None
25- options : List [Classification ] = field (default_factory = list )
31+ options : List [" Classification" ] = field (default_factory = list )
2632
2733 @property
2834 def label (self ):
2935 return self .value
3036
31- def to_dict (self , for_different_project = False ) -> Dict [str , str ]:
37+ def asdict (self ) -> Dict [str , str ]:
3238 return {
33- "schemaNodeId" : None if for_different_project else self .schema_id ,
34- "featureSchemaId" : None if for_different_project else self .feature_schema_id ,
39+ "schemaNodeId" : self .schema_id ,
40+ "featureSchemaId" : self .feature_schema_id ,
3541 "label" : self .label ,
3642 "value" : self .value ,
37- "options" : [classification . to_dict ( for_different_project ) for classification in self .options ]
43+ "options" : [c . asdict ( ) for c in self .options ]
3844 }
3945
4046 @classmethod
4147 def from_dict (cls , dictionary : Dict [str ,str ]):
42- def has_nested_classifications (dictionary : Dict [str ,str ]):
43- return [Classification .from_dict (nested_class ) for nested_class in dictionary .get ("options" , [])]
44-
4548 return Option (
4649 value = dictionary ["value" ],
4750 schema_id = dictionary ["schemaNodeId" ],
4851 feature_schema_id = dictionary ["featureSchemaId" ],
49- options = has_nested_classifications ( dictionary )
52+ options = [ Classification . from_dict ( nested_class ) for nested_class in dictionary . get ( "options" , [])]
5053 )
5154
52- def add_nested_class (self , * args , ** kwargs ):
53- new_classification = Classification (* args , ** kwargs )
54- if new_classification .instructions in (classification .instructions for classification in self .options ):
55- raise InconsistentOntologyException (f"Duplicate nested classification '{ new_classification .instructions } ' for option '{ self .label } '" )
56- self .options .append (new_classification )
57- return new_classification
55+ def add_option (self , * args , ** kwargs ):
56+ new_option = Classification (* args , ** kwargs )
57+ if new_option .instructions in (c .instructions for c in self .options ):
58+ raise InconsistentOntologyException (f"Duplicate nested classification '{ new_option .instructions } ' for option '{ self .label } '" )
59+ self .options .append (new_option )
60+ return new_option
5861
5962@dataclass
6063class Classification :
@@ -65,32 +68,30 @@ class Type(Enum):
6568 RADIO = "radio"
6669 DROPDOWN = "dropdown"
6770
71+ _REQUIRES_OPTIONS = set ((Type .CHECKLIST , Type .RADIO , Type .DROPDOWN ))
72+
6873 class_type : Type
6974 instructions : str
7075 required : bool = False
7176 options : List [Option ] = field (default_factory = list )
7277 schema_id : Optional [str ] = None
7378 feature_schema_id : Optional [str ] = None
7479
75- @staticmethod
76- def requires_options ():
77- return set ((Classification .Type .CHECKLIST , Classification .Type .RADIO , Classification .Type .DROPDOWN ))
78-
7980 @property
8081 def name (self ):
8182 return self .instructions
8283
83- def to_dict (self , for_different_project = False ) -> Dict [str ,str ]:
84- if self .class_type in Classification .requires_options () and len (self .options ) < 1 :
84+ def asdict (self ) -> Dict [str ,str ]:
85+ if self .class_type in Classification ._REQUIRES_OPTIONS and len (self .options ) < 1 :
8586 raise InconsistentOntologyException (f"Classification '{ self .instructions } ' requires options." )
8687 return {
8788 "type" : self .class_type .value ,
8889 "instructions" : self .instructions ,
8990 "name" : self .name ,
9091 "required" : self .required ,
91- "options" : [option . to_dict ( for_different_project ) for option in self .options ],
92- "schemaNodeId" : None if for_different_project else self .schema_id ,
93- "featureSchemaId" : None if for_different_project else self .feature_schema_id
92+ "options" : [o . asdict ( ) for o in self .options ],
93+ "schemaNodeId" : self .schema_id ,
94+ "featureSchemaId" : self .feature_schema_id
9495 }
9596
9697 @classmethod
@@ -99,14 +100,14 @@ def from_dict(cls, dictionary: Dict[str,str]):
99100 class_type = Classification .Type (dictionary ["type" ]),
100101 instructions = dictionary ["instructions" ],
101102 required = dictionary ["required" ],
102- options = [Option .from_dict (option ) for option in dictionary ["options" ]],
103+ options = [Option .from_dict (o ) for o in dictionary ["options" ]],
103104 schema_id = dictionary ["schemaNodeId" ],
104105 feature_schema_id = dictionary ["schemaNodeId" ]
105106 )
106107
107108 def add_option (self , * args , ** kwargs ):
108109 new_option = Option (* args , ** kwargs )
109- if new_option .value in (option .value for option in self .options ):
110+ if new_option .value in (o .value for o in self .options ):
110111 raise InconsistentOntologyException (f"Duplicate option '{ new_option .value } ' for classification '{ self .name } '." )
111112 self .options .append (new_option )
112113 return new_option
@@ -130,15 +131,15 @@ class Type(Enum):
130131 schema_id : Optional [str ] = None
131132 feature_schema_id : Optional [str ] = None
132133
133- def to_dict (self , for_different_project = False ) -> Dict [str ,str ]:
134+ def asdict (self ) -> Dict [str ,str ]:
134135 return {
135136 "tool" : self .tool .value ,
136137 "name" : self .name ,
137138 "required" : self .required ,
138139 "color" : self .color ,
139- "classifications" : [classification . to_dict ( for_different_project ) for classification in self .classifications ],
140- "schemaNodeId" : None if for_different_project else self .schema_id ,
141- "featureSchemaId" : None if for_different_project else self .feature_schema_id
140+ "classifications" : [c . asdict ( ) for c in self .classifications ],
141+ "schemaNodeId" : self .schema_id ,
142+ "featureSchemaId" : self .feature_schema_id
142143 }
143144
144145 @classmethod
@@ -149,13 +150,13 @@ def from_dict(cls, dictionary: Dict[str,str]):
149150 feature_schema_id = dictionary ["featureSchemaId" ],
150151 required = dictionary ["required" ],
151152 tool = Tool .Type (dictionary ["tool" ]),
152- classifications = [Classification .from_dict (classification ) for classification in dictionary ["classifications" ]],
153+ classifications = [Classification .from_dict (c ) for c in dictionary ["classifications" ]],
153154 color = dictionary ["color" ]
154155 )
155156
156157 def add_nested_class (self , * args , ** kwargs ):
157158 new_classification = Classification (* args , ** kwargs )
158- if new_classification .instructions in (classification .instructions for classification in self .classifications ):
159+ if new_classification .instructions in (c .instructions for c in self .classifications ):
159160 raise InconsistentOntologyException (f"Duplicate nested classification '{ new_classification .instructions } ' for option '{ self .label } '" )
160161 self .classifications .append (new_classification )
161162 return new_classification
@@ -168,8 +169,6 @@ class Ontology:
168169
169170 @classmethod
170171 def from_project (cls , project : Project ):
171- #TODO: consider if this should take in a Project object, or the project.uid.
172- #if we take in project.uid, we need to then get the project from a client object.
173172 ontology = project .ontology ().normalized
174173 return_ontology = Ontology ()
175174
@@ -183,34 +182,29 @@ def from_project(cls, project: Project):
183182
184183 def add_tool (self , * args , ** kwargs ) -> Tool :
185184 new_tool = Tool (* args , ** kwargs )
186- if new_tool .name in (tool .name for tool in self .tools ):
185+ if new_tool .name in (t .name for t in self .tools ):
187186 raise InconsistentOntologyException (f"Duplicate tool name '{ new_tool .name } '. " )
188187 self .tools .append (new_tool )
189188 return new_tool
190189
191190 def add_classification (self , * args , ** kwargs ) -> Classification :
192191 new_classification = Classification (* args , ** kwargs )
193- if new_classification .instructions in (classification .instructions for classification in self .classifications ):
192+ if new_classification .instructions in (c .instructions for c in self .classifications ):
194193 raise InconsistentOntologyException (f"Duplicate classifications instructions '{ new_classification .instructions } '. " )
195194 self .classifications .append (new_classification )
196195 return new_classification
197196
198- def build (self , for_different_project = False ):
197+ def asdict (self ):
199198 all_tools = []
200199 all_classifications = []
201200
202201 for tool in self .tools :
203- all_tools .append (tool .to_dict ( for_different_project ))
202+ all_tools .append (tool .asdict ( ))
204203
205204 for classification in self .classifications :
206- all_classifications .append (classification .to_dict ( for_different_project ))
205+ all_classifications .append (classification .asdict ( ))
207206
208207 return {"tools" : all_tools , "classifications" : all_classifications }
209208
210209if __name__ == "__main__" :
211- pass
212-
213-
214-
215-
216-
210+ pass
0 commit comments