tricc-oo 1.5.13__py3-none-any.whl → 1.6.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. tests/build.py +20 -28
  2. tests/test_build.py +260 -0
  3. tests/test_cql.py +48 -109
  4. tests/to_ocl.py +15 -17
  5. tricc_oo/__init__.py +0 -6
  6. tricc_oo/converters/codesystem_to_ocl.py +51 -40
  7. tricc_oo/converters/cql/cqlLexer.py +1 -0
  8. tricc_oo/converters/cql/cqlListener.py +1 -0
  9. tricc_oo/converters/cql/cqlParser.py +1 -0
  10. tricc_oo/converters/cql/cqlVisitor.py +1 -0
  11. tricc_oo/converters/cql_to_operation.py +129 -123
  12. tricc_oo/converters/datadictionnary.py +45 -54
  13. tricc_oo/converters/drawio_type_map.py +146 -65
  14. tricc_oo/converters/tricc_to_xls_form.py +58 -28
  15. tricc_oo/converters/utils.py +4 -4
  16. tricc_oo/converters/xml_to_tricc.py +296 -235
  17. tricc_oo/models/__init__.py +2 -1
  18. tricc_oo/models/base.py +333 -305
  19. tricc_oo/models/calculate.py +66 -51
  20. tricc_oo/models/lang.py +26 -27
  21. tricc_oo/models/ocl.py +146 -161
  22. tricc_oo/models/ordered_set.py +15 -19
  23. tricc_oo/models/tricc.py +149 -89
  24. tricc_oo/parsers/xml.py +15 -30
  25. tricc_oo/serializers/planuml.py +4 -6
  26. tricc_oo/serializers/xls_form.py +110 -153
  27. tricc_oo/strategies/input/base_input_strategy.py +28 -32
  28. tricc_oo/strategies/input/drawio.py +59 -71
  29. tricc_oo/strategies/output/base_output_strategy.py +151 -65
  30. tricc_oo/strategies/output/dhis2_form.py +908 -0
  31. tricc_oo/strategies/output/fhir_form.py +377 -0
  32. tricc_oo/strategies/output/html_form.py +224 -0
  33. tricc_oo/strategies/output/openmrs_form.py +694 -0
  34. tricc_oo/strategies/output/spice.py +106 -127
  35. tricc_oo/strategies/output/xls_form.py +322 -244
  36. tricc_oo/strategies/output/xlsform_cdss.py +627 -142
  37. tricc_oo/strategies/output/xlsform_cht.py +252 -125
  38. tricc_oo/strategies/output/xlsform_cht_hf.py +13 -24
  39. tricc_oo/visitors/tricc.py +1424 -1033
  40. tricc_oo/visitors/utils.py +16 -16
  41. tricc_oo/visitors/xform_pd.py +91 -89
  42. {tricc_oo-1.5.13.dist-info → tricc_oo-1.6.8.dist-info}/METADATA +128 -84
  43. tricc_oo-1.6.8.dist-info/RECORD +52 -0
  44. tricc_oo-1.6.8.dist-info/licenses/LICENSE +373 -0
  45. {tricc_oo-1.5.13.dist-info → tricc_oo-1.6.8.dist-info}/top_level.txt +0 -0
  46. tricc_oo-1.5.13.dist-info/RECORD +0 -46
  47. {tricc_oo-1.5.13.dist-info → tricc_oo-1.6.8.dist-info}/WHEEL +0 -0
tricc_oo/models/ocl.py CHANGED
@@ -1,59 +1,34 @@
1
1
  # https://docs.openconceptlab.org/
2
2
 
3
- from enum import Enum
4
- from typing import Dict, List, Optional, Union, Literal, Annotated
5
- from xml.dom import HIERARCHY_REQUEST_ERR
3
+ from typing import Annotated, Dict, List, Literal, Union
6
4
  from xmlrpc.client import Boolean
7
- from pydantic import BaseModel, constr, AnyHttpUrl, StringConstraints
8
- from ocldev.oclconstants import OclConstants, OclConstants as OclConstantsBase
9
-
10
- OCLId = Annotated[
11
- str,
12
- StringConstraints(pattern=r"^.+$")
13
- ]
14
- OCLName = Annotated[
15
- str,
16
- StringConstraints(pattern=r"^.+$")
17
- ]
18
- OCLShortName = Annotated[
19
- str,
20
- StringConstraints(pattern=r"^.+$")
21
- ]
22
- OCLLocale = Annotated[
23
- str,
24
- StringConstraints(pattern=r"^[a-zA-Z\-]{2,7}$")
25
- ]
26
- Uri = Annotated[
27
- str,
28
- StringConstraints(pattern=r"^.+$")
29
- ]
30
- OCLMapCode = Annotated[
31
- str,
32
- StringConstraints(pattern=r"^.+$")
33
- ]
5
+ from pydantic import AnyHttpUrl, BaseModel, StringConstraints
6
+ from ocldev.oclconstants import OclConstants as OclConstantsBase
34
7
 
8
+ OCLId = Annotated[str, StringConstraints(pattern=r"^.+$")]
9
+ OCLName = Annotated[str, StringConstraints(pattern=r"^.+$")]
10
+ OCLShortName = Annotated[str, StringConstraints(pattern=r"^.+$")]
11
+ OCLLocale = Annotated[str, StringConstraints(pattern=r"^[a-zA-Z\-]{2,7}$")]
12
+ Uri = Annotated[str, StringConstraints(pattern=r"^.+$")]
13
+ OCLMapCode = Annotated[str, StringConstraints(pattern=r"^.+$")]
35
14
 
36
15
 
37
16
  class OclConstants(OclConstantsBase):
38
- #OCL Access type
39
- ACCESS_TYPE_VIEW = 'View'
40
- ACCESS_TYPE_EDIT = 'Edit'
41
- ACCESS_TYPE_NONE = 'None'
42
- ACCESS_TYPES = [
43
- ACCESS_TYPE_EDIT,
44
- ACCESS_TYPE_VIEW,
45
- ACCESS_TYPE_NONE
46
- ]
47
- #https://www.hl7.org/fhir/valueset-codesystem-hierarchy-meaning.html
48
- HIERARCHY_MEANING_IS_A = 'is-a'
49
- HIERARCHY_MEANING_GROUP_BY = 'grouped-by'
50
- HIERARCHY_MEANING_PART_OF = 'part-of'
51
- HIERARCHY_MEANING_CLASSIFIED_WITH = ' classified-with'
17
+ # OCL Access type
18
+ ACCESS_TYPE_VIEW = "View"
19
+ ACCESS_TYPE_EDIT = "Edit"
20
+ ACCESS_TYPE_NONE = "None"
21
+ ACCESS_TYPES = [ACCESS_TYPE_EDIT, ACCESS_TYPE_VIEW, ACCESS_TYPE_NONE]
22
+ # https://www.hl7.org/fhir/valueset-codesystem-hierarchy-meaning.html
23
+ HIERARCHY_MEANING_IS_A = "is-a"
24
+ HIERARCHY_MEANING_GROUP_BY = "grouped-by"
25
+ HIERARCHY_MEANING_PART_OF = "part-of"
26
+ HIERARCHY_MEANING_CLASSIFIED_WITH = " classified-with"
52
27
  HIERARCHY_MEANINGS = [
53
28
  HIERARCHY_MEANING_IS_A,
54
29
  HIERARCHY_MEANING_GROUP_BY,
55
30
  HIERARCHY_MEANING_PART_OF,
56
- HIERARCHY_MEANING_CLASSIFIED_WITH
31
+ HIERARCHY_MEANING_CLASSIFIED_WITH,
57
32
  ]
58
33
  SOURCE_TYPE_DICTIONARY = "Dictionary"
59
34
  SOURCE_TYPE_REFERENCE = "Reference"
@@ -61,7 +36,7 @@ class OclConstants(OclConstantsBase):
61
36
  SOURCE_TYPES = [
62
37
  SOURCE_TYPE_DICTIONARY,
63
38
  SOURCE_TYPE_REFERENCE,
64
- SOURCE_TYPE_EXTERNAL_DICTIONARY
39
+ SOURCE_TYPE_EXTERNAL_DICTIONARY,
65
40
  ]
66
41
  # MAP type found for fever/malaria on OCL app
67
42
  MAP_TYPE_SAME_AS = "SAME-AS"
@@ -86,7 +61,7 @@ class OclConstants(OclConstantsBase):
86
61
  MAP_TYPE_HAS_ELEMENT,
87
62
  MAP_TYPE_MAP_TO,
88
63
  ]
89
- DATA_TYPE_BOOLEAN = 'Boolean'
64
+ DATA_TYPE_BOOLEAN = "Boolean"
90
65
  DATA_TYPE_COMPLEX = "Complex"
91
66
  DATA_TYPE_STRUCTURED_NUMERIC = "Structured-Numeric"
92
67
  DATA_TYPE_RULE = "Rule"
@@ -100,7 +75,7 @@ class OclConstants(OclConstantsBase):
100
75
  DATA_TYPE_NA = "N/A"
101
76
  DATA_TYPE_NUMERIC = "Numeric"
102
77
  DATA_TYPE_NONE = "None"
103
- DATA_TYPES =[
78
+ DATA_TYPES = [
104
79
  DATA_TYPE_BOOLEAN,
105
80
  DATA_TYPE_CODED,
106
81
  DATA_TYPE_STRING,
@@ -114,15 +89,11 @@ class OclConstants(OclConstantsBase):
114
89
  DATA_TYPE_DATETIME,
115
90
  DATA_TYPE_TIME,
116
91
  DATA_TYPE_DATE,
117
- DATA_TYPE_DOCUMENT
92
+ DATA_TYPE_DOCUMENT,
118
93
  ]
119
94
  DESCRIPTION_TYPE_DEFINITION = "Definition"
120
95
  DESCRIPTION_TYPE_NONE = "None"
121
- DESCRIPTION_TYPES = [
122
- DESCRIPTION_TYPE_DEFINITION,
123
- DESCRIPTION_TYPE_NONE
124
-
125
- ]
96
+ DESCRIPTION_TYPES = [DESCRIPTION_TYPE_DEFINITION, DESCRIPTION_TYPE_NONE]
126
97
  NAME_TYPE_INDEX_TERM = "Index-Term"
127
98
  NAME_TYPE_SHORT = "Short"
128
99
  NAME_TYPE_FULLY_SPECIFIED = "Fully-Specified"
@@ -131,151 +102,165 @@ class OclConstants(OclConstantsBase):
131
102
  NAME_TYPE_INDEX_TERM,
132
103
  NAME_TYPE_SHORT,
133
104
  NAME_TYPE_FULLY_SPECIFIED,
134
- NAME_TYPE_NONE
105
+ NAME_TYPE_NONE,
135
106
  ]
136
- OCLRessourceType= Literal[tuple(OclConstants.RESOURCE_TYPES)]
107
+
108
+
109
+ OCLRessourceType = Literal[tuple(OclConstants.RESOURCE_TYPES)]
137
110
 
138
111
 
139
112
  def get_data_type(tricc_type):
140
- if tricc_type.lower() in ('integer', 'decimal', 'add', 'count'):
113
+ if tricc_type.lower() in ("integer", "decimal", "add", "count"):
141
114
  return OclConstants.DATA_TYPE_NUMERIC
142
- elif tricc_type.lower() in ('activity', 'page'):
115
+ elif tricc_type.lower() in ("activity", "page"):
143
116
  return OclConstants.DATA_TYPE_DOCUMENT
144
- elif tricc_type.lower() in ('select_one'):
117
+ elif tricc_type.lower() in ("select_one"):
145
118
  return OclConstants.DATA_TYPE_CODED
146
- elif tricc_type.lower() in ('calculate', 'diagnosis', 'proposed_diagnosis'):
119
+ elif tricc_type.lower() in ("calculate", "diagnosis", "proposed_diagnosis"):
147
120
  return OclConstants.DATA_TYPE_BOOLEAN
148
- found_type = [ t for t in OclConstants.DATA_TYPES if t.lower() == tricc_type.lower()]
121
+ found_type = [t for t in OclConstants.DATA_TYPES if t.lower() == tricc_type.lower()]
149
122
  if found_type:
150
123
  return found_type[0]
151
124
  return OclConstants.DATA_TYPE_NA
152
-
125
+
126
+
153
127
  class OCLBaseModel(BaseModel):
154
- type:OCLRessourceType
155
- id:OCLId
156
- external_id:str = None
157
- public_access:Literal[tuple(OclConstants.ACCESS_TYPES)] = OclConstants.ACCESS_TYPE_VIEW
158
- extras:Dict[str,Union[str,Dict[str,str]]] = {}
159
- url: Union[AnyHttpUrl,Uri] = None
128
+ type: OCLRessourceType
129
+ id: OCLId
130
+ external_id: str = None
131
+ public_access: Literal[tuple(OclConstants.ACCESS_TYPES)] = OclConstants.ACCESS_TYPE_VIEW
132
+ extras: Dict[str, Union[str, Dict[str, str]]] = {}
133
+ url: Union[AnyHttpUrl, Uri] = None
160
134
  # enriched data for get
135
+
136
+
161
137
  class OclGet(BaseModel):
162
- created_on:str = None
163
- created_by:str = None
164
- updated_on:str = None
165
- updated_by:str = None
166
-
138
+ created_on: str = None
139
+ created_by: str = None
140
+ updated_on: str = None
141
+ updated_by: str = None
142
+
143
+
167
144
  class OCLBaseModelBrowsable(OCLBaseModel):
168
- name:OCLName
169
- description:str = None
170
- website:AnyHttpUrl = None
171
-
145
+ name: OCLName
146
+ description: str = None
147
+ website: AnyHttpUrl = None
148
+
172
149
 
173
150
  class OCLDetailedName(BaseModel):
174
151
  name: str
175
- external_id:str = None
176
- locale:OCLLocale
177
- locale_preferred:Boolean = None
178
- name_type:Literal[tuple(OclConstants.NAME_TYPES)] = OclConstants.NAME_TYPE_SHORT
152
+ external_id: str = None
153
+ locale: OCLLocale
154
+ locale_preferred: Boolean = None
155
+ name_type: Literal[tuple(OclConstants.NAME_TYPES)] = OclConstants.NAME_TYPE_SHORT
156
+
179
157
 
180
158
  class OCLDetailedDescription(BaseModel):
181
- description:str
182
- external_id:str = None
183
- locale:OCLLocale
184
- locale_preferred:Boolean = None
185
- description_type:Literal[tuple(OclConstants.DESCRIPTION_TYPES)] = OclConstants.DESCRIPTION_TYPE_DEFINITION
159
+ description: str
160
+ external_id: str = None
161
+ locale: OCLLocale
162
+ locale_preferred: Boolean = None
163
+ description_type: Literal[tuple(OclConstants.DESCRIPTION_TYPES)] = OclConstants.DESCRIPTION_TYPE_DEFINITION
164
+
186
165
 
187
166
  class OCLConcept(OCLBaseModel):
188
- type:OCLRessourceType = OclConstants.RESOURCE_TYPE_CONCEPT
167
+ type: OCLRessourceType = OclConstants.RESOURCE_TYPE_CONCEPT
189
168
  uuid: str = None
190
169
  concept_class: str
191
- datatype:Literal[tuple(OclConstants.DATA_TYPES)] = OclConstants.DATA_TYPE_NONE
192
- names:List[OCLDetailedName]
170
+ datatype: Literal[tuple(OclConstants.DATA_TYPES)] = OclConstants.DATA_TYPE_NONE
171
+ names: List[OCLDetailedName]
193
172
  descriptions: List[OCLDetailedDescription] = []
194
- retired:Boolean = False
173
+ retired: Boolean = False
195
174
  # not for create
196
- versions: str = None # TODO version
197
- source:OCLId = None
198
- owner:OCLId = None
199
- owner_type:Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM)] = None
200
- owner_url:Union[AnyHttpUrl,Uri] = None
201
- versions_url:Union[AnyHttpUrl,Uri] = None
202
- source_url:Union[AnyHttpUrl,Uri] = None
203
- owner_url:Union[AnyHttpUrl,Uri] = None
204
- mappings_url:Union[AnyHttpUrl,Uri] = None
205
-
175
+ versions: str = None # TODO version
176
+ source: OCLId = None
177
+ owner: OCLId = None
178
+ owner_type: Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM)] = None
179
+ owner_url: Union[AnyHttpUrl, Uri] = None
180
+ versions_url: Union[AnyHttpUrl, Uri] = None
181
+ source_url: Union[AnyHttpUrl, Uri] = None
182
+ owner_url: Union[AnyHttpUrl, Uri] = None
183
+ mappings_url: Union[AnyHttpUrl, Uri] = None
184
+
185
+
206
186
  class OCLMapping(BaseModel):
207
- type:OCLRessourceType = OclConstants.RESOURCE_TYPE_MAPPING
187
+ type: OCLRessourceType = OclConstants.RESOURCE_TYPE_MAPPING
208
188
  uuid: str = None
209
- retired:Boolean = False
189
+ retired: Boolean = False
210
190
  map_type: Literal[tuple(OclConstants.MAP_TYPES)]
211
- from_concept_url:Union[AnyHttpUrl,Uri]
212
- from_source_url:Uri = None
213
- from_concept_code:str = None
214
- from_concept_name:str = None
215
- to_concept_url:Union[AnyHttpUrl,Uri] = None
216
- to_source:str = None
217
- to_concept_code:str = None
218
- to_source_owner:OCLId = None
219
- to_source_owner_type:Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM)] = None
220
- #for bulk
221
- source:OCLId = None
222
- owner:OCLId = None
223
- owner_type:Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM.values())] = None
191
+ from_concept_url: Union[AnyHttpUrl, Uri]
192
+ from_source_url: Uri = None
193
+ from_concept_code: str = None
194
+ from_concept_name: str = None
195
+ to_concept_url: Union[AnyHttpUrl, Uri] = None
196
+ to_source: str = None
197
+ to_concept_code: str = None
198
+ to_source_owner: OCLId = None
199
+ to_source_owner_type: Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM)] = None
200
+ # for bulk
201
+ source: OCLId = None
202
+ owner: OCLId = None
203
+ owner_type: Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM.values())] = None
204
+
224
205
 
225
206
  class OCLCollection(OCLBaseModelBrowsable):
226
- #TODO https://docs.openconceptlab.org/en/latest/oclapi/apireference/collections.html
207
+ # TODO https://docs.openconceptlab.org/en/latest/oclapi/apireference/collections.html
227
208
  pass
228
209
 
210
+
229
211
  class OCLUser(OCLBaseModelBrowsable):
230
- #TODO https://docs.openconceptlab.org/en/latest/oclapi/apireference/users.html
231
- pass
232
-
233
- class OCLMappingInternal(OCLMapping):
234
- to_concept_url:Union[AnyHttpUrl,Uri]
212
+ # TODO https://docs.openconceptlab.org/en/latest/oclapi/apireference/users.html
213
+ pass
214
+
215
+
216
+ class OCLMappingInternal(OCLMapping):
217
+ to_concept_url: Union[AnyHttpUrl, Uri]
235
218
  # when there is not URL
236
-
237
- class OCLMappingExternal(OCLMapping):
238
- to_source_url:Uri
239
- to_concept_code:str
240
- to_concept_name:str = None
241
-
219
+
220
+
221
+ class OCLMappingExternal(OCLMapping):
222
+ to_source_url: Uri
223
+ to_concept_code: str
224
+ to_concept_name: str = None
225
+
226
+
242
227
  class OCLOrganisation(OCLBaseModelBrowsable):
243
- type:OCLRessourceType = OclConstants.RESOURCE_TYPE_ORGANIZATION
244
- company:OCLName
245
- logo_url:AnyHttpUrl
246
- location:OCLName
247
- text:str
248
-
249
-
228
+ type: OCLRessourceType = OclConstants.RESOURCE_TYPE_ORGANIZATION
229
+ company: OCLName
230
+ logo_url: AnyHttpUrl
231
+ location: OCLName
232
+ text: str
233
+
250
234
 
251
235
  class OCLSource(OCLBaseModelBrowsable):
252
- type:OCLRessourceType = OclConstants.RESOURCE_TYPE_SOURCE
253
- short_code:OCLShortName
254
- full_name:OCLName
255
- source_type:Literal[tuple(OclConstants.SOURCE_TYPES)] = OclConstants.SOURCE_TYPE_DICTIONARY
256
- default_locale:OCLLocale = 'en'
257
- supported_locales:List[OCLLocale] = ['en']
258
- custom_validation_schema:str = 'None'
236
+ type: OCLRessourceType = OclConstants.RESOURCE_TYPE_SOURCE
237
+ short_code: OCLShortName
238
+ full_name: OCLName
239
+ source_type: Literal[tuple(OclConstants.SOURCE_TYPES)] = OclConstants.SOURCE_TYPE_DICTIONARY
240
+ default_locale: OCLLocale = "en"
241
+ supported_locales: List[OCLLocale] = ["en"]
242
+ custom_validation_schema: str = "None"
259
243
  # not for create
260
- owner:OCLId = None
261
- owner_type:Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM)] = None
262
- owner_url:Union[AnyHttpUrl,Uri] = None
263
- #FHIR
264
- hierarchy_meaning:Literal[tuple(OclConstants.HIERARCHY_MEANINGS)] = None
265
- hierarchy_root_url:Union[AnyHttpUrl,Uri] = None
266
- meta:str = None
267
- canonical_url:Union[AnyHttpUrl,Uri] = None
268
- internal_reference_id:OCLId = None
269
- #collection_reference:Uri
270
- versions_url:Union[AnyHttpUrl,Uri] = None
271
- concepts_url:Union[AnyHttpUrl,Uri] = None
272
- mappings_url:Union[AnyHttpUrl,Uri] = None
273
-
274
- versions: str = None # TODO version
275
- active_concepts:int = 0
276
- active_mappings:int = 0
277
-
244
+ owner: OCLId = None
245
+ owner_type: Literal[tuple(OclConstants.OWNER_TYPE_TO_STEM)] = None
246
+ owner_url: Union[AnyHttpUrl, Uri] = None
247
+ # FHIR
248
+ hierarchy_meaning: Literal[tuple(OclConstants.HIERARCHY_MEANINGS)] = None
249
+ hierarchy_root_url: Union[AnyHttpUrl, Uri] = None
250
+ meta: str = None
251
+ canonical_url: Union[AnyHttpUrl, Uri] = None
252
+ internal_reference_id: OCLId = None
253
+ # collection_reference:Uri
254
+ versions_url: Union[AnyHttpUrl, Uri] = None
255
+ concepts_url: Union[AnyHttpUrl, Uri] = None
256
+ mappings_url: Union[AnyHttpUrl, Uri] = None
257
+
258
+ versions: str = None # TODO version
259
+ active_concepts: int = 0
260
+ active_mappings: int = 0
261
+
262
+
278
263
  class OCLSourceVersion(OCLBaseModelBrowsable):
279
264
  released: Boolean = None
280
- previous_version :str
281
- parent_version :str
265
+ previous_version: str
266
+ parent_version: str
@@ -1,8 +1,9 @@
1
1
  from collections import OrderedDict
2
2
  from collections.abc import Iterable, Sequence
3
- from pydantic import BaseModel, GetCoreSchemaHandler
3
+ from pydantic import GetCoreSchemaHandler
4
4
  from pydantic_core import CoreSchema
5
5
 
6
+
6
7
  class OrderedSet(Sequence):
7
8
  def __init__(self, iterable=None):
8
9
  self._od = OrderedDict.fromkeys(iterable or [])
@@ -20,14 +21,15 @@ class OrderedSet(Sequence):
20
21
  return self._od.popitem(last=False)[0]
21
22
 
22
23
  def insert_at_top(self, item):
23
- # Add item if not already present
24
+ # Add item if not already present
24
25
  self.insert_at_bottom(item)
25
26
  # Move item to the top
26
27
  self._od.move_to_end(item, last=False)
27
-
28
+
28
29
  def insert_at_bottom(self, item):
29
30
  if item not in self._od:
30
31
  self._od[item] = None
32
+
31
33
  def __contains__(self, item):
32
34
  return item in self._od
33
35
 
@@ -44,12 +46,13 @@ class OrderedSet(Sequence):
44
46
  for item in items:
45
47
  if item not in self:
46
48
  self.insert_at_bottom(item)
49
+
47
50
  def __eq__(self, other):
48
51
  if not isinstance(other, self.__class__):
49
52
  return False
50
53
  else:
51
54
  return self._od.keys() == other._od.keys()
52
-
55
+
53
56
  # Union method (| operator)
54
57
  def __or__(self, other):
55
58
  if not isinstance(other, Iterable):
@@ -60,32 +63,26 @@ class OrderedSet(Sequence):
60
63
 
61
64
  def union(self, other):
62
65
  return self.__or__(other)
63
- def __or__(self, other):
64
- if not isinstance(other, Iterable):
65
- raise TypeError("Unsupported operand type(s) for |: 'OrderedSet' and '{}'".format(type(other)))
66
- new_set = self.copy()
67
- new_set._add_items(other)
68
- return new_set
69
-
66
+
70
67
  def __iadd__(self, other):
71
68
  if not isinstance(other, Iterable):
72
69
  raise TypeError("Unsupported operand type(s) for +=: 'OrderedSet' and '{}'".format(type(other)))
73
70
  self._add_items(other)
74
71
  return self
75
-
72
+
76
73
  def get(self, index):
77
74
  return self.__getitem__(index)
78
-
75
+
79
76
  def __getitem__(self, index):
80
77
  try:
81
78
  return list(self._od.keys())[index]
82
79
  except IndexError:
83
80
  raise IndexError("Index out of range") from None
84
-
81
+
85
82
  def sort(self, key=None, reverse=False):
86
83
  sorted_keys = sorted(self._od.keys(), key=key, reverse=reverse)
87
84
  self._od = OrderedDict.fromkeys(sorted_keys)
88
-
85
+
89
86
  def find_last(self, filter: callable):
90
87
  # Iterate over items in reverse order
91
88
  for item in reversed(list(self._od.keys())):
@@ -99,24 +96,23 @@ class OrderedSet(Sequence):
99
96
  return item
100
97
  return None # Return None if no matching item is found
101
98
 
102
-
103
99
  def find_prev(self, obj, filter: callable):
104
100
  # Get the list of keys (items) in the OrderedSet
105
101
  keys = list(self._od.keys())
106
-
102
+
107
103
  # If the object is not in the OrderedSet, start from the end
108
104
  if obj not in self._od:
109
105
  start_index = len(keys)
110
106
  else:
111
107
  # Find the index of the given object
112
108
  start_index = keys.index(obj)
113
-
109
+
114
110
  # Iterate backward from the start_index
115
111
  for i in range(start_index - 1, -1, -1):
116
112
  item = keys[i]
117
113
  if filter(item):
118
114
  return item
119
-
115
+
120
116
  return None # Return None if no matching item is found before the object
121
117
 
122
118
  @classmethod