@@ -49,7 +49,7 @@ class Group(HLObject, MutableMappingHDF5):
49
49
""" Represents an HDF5 group.
50
50
"""
51
51
52
- def __init__ (self , bind , ** kwargs ):
52
+ def __init__ (self , bind , track_order = False , ** kwargs ):
53
53
# print "group init, bind:", bind
54
54
55
55
""" Create a new Group object by binding to a low-level GroupID.
@@ -58,6 +58,7 @@ def __init__(self, bind, **kwargs):
58
58
if not isinstance (bind , GroupID ):
59
59
raise ValueError (f"{ bind } is not a GroupID" )
60
60
HLObject .__init__ (self , bind , ** kwargs )
61
+ self ._track_order = track_order
61
62
self ._req_prefix = "/groups/" + self .id .uuid
62
63
self ._link_db = {} # cache for links
63
64
@@ -149,7 +150,7 @@ def _get_link_json(self, h5path):
149
150
req = "/groups/" + parent_uuid + "/links/" + name
150
151
151
152
try :
152
- rsp_json = self .GET (req )
153
+ rsp_json = self .GET (req , params = { "CreateOrder" : "1" if self . _track_order else "0" } )
153
154
except IOError :
154
155
raise KeyError ("Unable to open object (Component not found)" )
155
156
@@ -181,7 +182,7 @@ def _get_objdb_links(self):
181
182
group_json = objdb [self .id .id ]
182
183
return group_json ["links" ]
183
184
184
- def create_group (self , h5path ):
185
+ def create_group (self , h5path , track_order = False ):
185
186
""" Create and return a new subgroup.
186
187
187
188
Name may be absolute or relative. Fails if the target name already
@@ -237,6 +238,7 @@ def create_group(self, h5path):
237
238
parent_name = parent_name + '/' + link
238
239
self .log .debug ("create group - parent name: {}" .format (parent_name ))
239
240
sub_group ._name = parent_name
241
+ sub_group ._track_order = track_order
240
242
parent_uuid = sub_group .id .id
241
243
else :
242
244
# sub-group already exsits
@@ -258,6 +260,7 @@ def create_group(self, h5path):
258
260
if sub_group is None :
259
261
# didn't actually create anything
260
262
raise ValueError ("name already exists" )
263
+
261
264
return sub_group
262
265
263
266
def create_dataset (self , name , shape = None , dtype = None , data = None , ** kwds ):
@@ -547,7 +550,7 @@ def require_group(self, name):
547
550
raise TypeError (f"Incompatible object ({ grp .__class__ .__name__ } ) already exists" )
548
551
return grp
549
552
550
- def getObjByUuid (self , uuid , collection_type = None ):
553
+ def getObjByUuid (self , uuid , collection_type = None , track_order = False ):
551
554
""" Utility method to get an obj based on collection type and uuid """
552
555
self .log .debug (f"getObjByUuid({ uuid } )" )
553
556
obj_json = None
@@ -582,10 +585,10 @@ def getObjByUuid(self, uuid, collection_type=None):
582
585
# will need to get JSON from server
583
586
req = f"/{ collection_type } /{ uuid } "
584
587
# make server request
585
- obj_json = self .GET (req )
588
+ obj_json = self .GET (req , params = { "CreateOrder" : "1" if track_order else "0" } )
586
589
587
590
if collection_type == 'groups' :
588
- tgt = Group (GroupID (self , obj_json ))
591
+ tgt = Group (GroupID (self , obj_json ), track_order = track_order )
589
592
elif collection_type == 'datatypes' :
590
593
tgt = Datatype (TypeID (self , obj_json ))
591
594
elif collection_type == 'datasets' :
@@ -595,13 +598,13 @@ def getObjByUuid(self, uuid, collection_type=None):
595
598
if "dims" in shape_json and len (shape_json ["dims" ]) == 1 and dtype_json ["class" ] == 'H5T_COMPOUND' :
596
599
tgt = Table (DatasetID (self , obj_json ))
597
600
else :
598
- tgt = Dataset (DatasetID (self , obj_json ))
601
+ tgt = Dataset (DatasetID (self , obj_json ), track_order = track_order )
599
602
else :
600
603
raise IOError (f"Unexpected collection_type: { collection_type } " )
601
604
602
605
return tgt
603
606
604
- def __getitem__ (self , name ):
607
+ def __getitem__ (self , name , track_order = False ):
605
608
""" Open an object in the file """
606
609
# convert bytes to str for PY3
607
610
if isinstance (name , bytes ):
@@ -614,11 +617,11 @@ def __getitem__(self, name):
614
617
if tgt is not None :
615
618
return tgt # ref'd object has not been deleted
616
619
if isinstance (name .id , GroupID ):
617
- tgt = self .getObjByUuid (name .id .uuid , collection_type = "groups" )
620
+ tgt = self .getObjByUuid (name .id .uuid , collection_type = "groups" , track_order = track_order )
618
621
elif isinstance (name .id , DatasetID ):
619
- tgt = self .getObjByUuid (name .id .uuid , collection_type = "datasets" )
622
+ tgt = self .getObjByUuid (name .id .uuid , collection_type = "datasets" , track_order = track_order )
620
623
elif isinstance (name .id , TypeID ):
621
- tgt = self .getObjByUuid (name .id .uuid , collection_type = "datasets" )
624
+ tgt = self .getObjByUuid (name .id .uuid , collection_type = "datasets" , track_order = track_order )
622
625
else :
623
626
raise IOError ("Unexpected Error - ObjectID type: " + name .__class__ .__name__ )
624
627
return tgt
@@ -631,11 +634,11 @@ def __getitem__(self, name):
631
634
link_class = link_json ['class' ]
632
635
633
636
if link_class == 'H5L_TYPE_HARD' :
634
- tgt = self .getObjByUuid (link_json ['id' ], collection_type = link_json ['collection' ])
637
+ tgt = self .getObjByUuid (link_json ['id' ], collection_type = link_json ['collection' ], track_order = track_order )
635
638
elif link_class == 'H5L_TYPE_SOFT' :
636
639
h5path = link_json ['h5path' ]
637
640
soft_parent_uuid , soft_json = self ._get_link_json (h5path )
638
- tgt = self .getObjByUuid (soft_json ['id' ], collection_type = soft_json ['collection' ])
641
+ tgt = self .getObjByUuid (soft_json ['id' ], collection_type = soft_json ['collection' ], track_order = track_order )
639
642
640
643
elif link_class == 'H5L_TYPE_EXTERNAL' :
641
644
# try to get a handle to the file and return the linked object...
@@ -651,7 +654,8 @@ def __getitem__(self, name):
651
654
endpoint = self .id .http_conn .endpoint
652
655
username = self .id .http_conn .username
653
656
password = self .id .http_conn .password
654
- f = File (external_domain , endpoint = endpoint , username = username , password = password , mode = 'r' )
657
+ f = File (external_domain , endpoint = endpoint , username = username , password = password , mode = 'r' ,
658
+ track_order = track_order )
655
659
except IOError :
656
660
# unable to find external link
657
661
raise KeyError ("Unable to open file: " + link_json ['h5domain' ])
@@ -675,7 +679,7 @@ def __getitem__(self, name):
675
679
tgt ._name = name
676
680
return tgt
677
681
678
- def get (self , name , default = None , getclass = False , getlink = False ):
682
+ def get (self , name , default = None , getclass = False , getlink = False , track_order = False ):
679
683
""" Retrieve an item or other information.
680
684
681
685
"name" given only:
@@ -699,18 +703,17 @@ def get(self, name, default=None, getclass=False, getlink=False):
699
703
>>> if cls == SoftLink:
700
704
... print '"foo" is a soft link!'
701
705
"""
702
-
703
706
if not (getclass or getlink ):
704
707
try :
705
- return self [ name ]
708
+ return self . __getitem__ ( name , track_order )
706
709
except KeyError :
707
710
return default
708
711
709
712
if name not in self :
710
713
return default
711
714
712
715
elif getclass and not getlink :
713
- obj = self .__getitem__ (name )
716
+ obj = self .__getitem__ (name , track_order )
714
717
if obj is None :
715
718
return None
716
719
if obj .id .__class__ is GroupID :
@@ -777,7 +780,7 @@ def __setitem__(self, name, obj):
777
780
raise IOError ("cannot create subgroup of softlink" )
778
781
parent_uuid = link_json ["id" ]
779
782
req = "/groups/" + parent_uuid
780
- group_json = self .GET (req )
783
+ group_json = self .GET (req , params = { "CreateOrder" : "1" if self . _track_order else "0" } )
781
784
tgt = Group (GroupID (self , group_json ))
782
785
tgt [basename ] = obj
783
786
@@ -867,7 +870,7 @@ def __len__(self):
867
870
return len (links_json )
868
871
869
872
req = "/groups/" + self .id .uuid
870
- rsp_json = self .GET (req )
873
+ rsp_json = self .GET (req , params = { "CreateOrder" : "1" if self . _track_order else "0" } )
871
874
return rsp_json ['linkCount' ]
872
875
873
876
def __iter__ (self ):
@@ -876,7 +879,7 @@ def __iter__(self):
876
879
877
880
if links is None :
878
881
req = "/groups/" + self .id .uuid + "/links"
879
- rsp_json = self .GET (req )
882
+ rsp_json = self .GET (req , params = { "CreateOrder" : "1" if self . _track_order else "0" } )
880
883
links = rsp_json ['links' ]
881
884
882
885
# reset the link cache
@@ -888,7 +891,16 @@ def __iter__(self):
888
891
for x in links :
889
892
yield x ['title' ]
890
893
else :
891
- for name in links :
894
+ if self ._track_order :
895
+ links = sorted (links .items (), key = lambda x : x [1 ]['created' ])
896
+ else :
897
+ links = sorted (links .items ())
898
+
899
+ ordered_links = {}
900
+ for link in links :
901
+ ordered_links [link [0 ]] = link [1 ]
902
+
903
+ for name in ordered_links :
892
904
yield name
893
905
894
906
def __contains__ (self , name ):
@@ -1092,7 +1104,7 @@ def visititems(self, func):
1092
1104
else :
1093
1105
# request from server
1094
1106
req = "/groups/" + parent .id .uuid + "/links"
1095
- rsp_json = self .GET (req )
1107
+ rsp_json = self .GET (req , params = { "CreateOrder" : "1" if self . _track_order else "0" } )
1096
1108
links = rsp_json ['links' ]
1097
1109
for link in links :
1098
1110
obj = None
@@ -1137,6 +1149,36 @@ def __repr__(self):
1137
1149
r = f'<HDF5 group { namestr } ({ len (self )} members)>'
1138
1150
return r
1139
1151
1152
+ def __reversed__ (self ):
1153
+ """ Iterate over member names in reverse order """
1154
+ links = self ._get_objdb_links ()
1155
+
1156
+ if links is None :
1157
+ req = "/groups/" + self .id .uuid + "/links"
1158
+ rsp_json = self .GET (req , params = {"CreateOrder" : "1" if self ._track_order else "0" })
1159
+ links = rsp_json ['links' ]
1160
+
1161
+ # reset the link cache
1162
+ self ._link_db = {}
1163
+ for link in links :
1164
+ name = link ["title" ]
1165
+ self ._link_db [name ] = link
1166
+
1167
+ for x in reversed (links ):
1168
+ yield x ['title' ]
1169
+ else :
1170
+ if self ._track_order :
1171
+ links = sorted (links .items (), key = lambda x : x [1 ]['created' ])
1172
+ else :
1173
+ links = sorted (links .items ())
1174
+
1175
+ ordered_links = {}
1176
+ for link in links :
1177
+ ordered_links [link [0 ]] = link [1 ]
1178
+
1179
+ for name in reversed (ordered_links ):
1180
+ yield name
1181
+
1140
1182
1141
1183
class HardLink (object ):
1142
1184
0 commit comments