66
77
88class CompoundChildFile :
9+ id : int
910 path : str
1011 url : str
1112 blob_path : str
@@ -24,8 +25,10 @@ class CompoundChildFile:
2425 video_split_duration : int
2526 local_id : str
2627 ordinal : int
28+ root_file : 'CompoundFile'
2729
2830 def __init__ (self ,
31+ root_file : 'CompoundFile' ,
2932 child_file_type : str ,
3033 path : str = None ,
3134 url : str = None ,
@@ -42,7 +45,9 @@ def __init__(self,
4245 assume_new_instances_machine_made : bool = None ,
4346 convert_names_to_label_files : bool = None ,
4447 video_split_duration : int = None ,
45- ordinal : int = 0 ):
48+ ordinal : int = 0 ,
49+ id : int = None ):
50+ self .root_file = root_file
4651 self .child_file_type = child_file_type
4752 self .path = path
4853 self .url = url
@@ -61,6 +66,38 @@ def __init__(self,
6166 self .video_split_duration = video_split_duration
6267 self .local_id = str (uuid4 ())
6368 self .ordinal = ordinal
69+ self .id = None
70+
71+ def __str__ (self ):
72+ return f'<CompoundChildFile id={ self .id } ordinal={ self .ordinal } file_name={ self .file_name } child_file_type={ self .child_file_type } >'
73+ def refresh_from_data_dict (self , data : dict ):
74+ if not data :
75+ return
76+ for key in data :
77+ setattr (self , key , data [key ])
78+
79+ def update (self ):
80+ """
81+ Syncs child file data with backend API
82+ :return:
83+ """
84+ payload = {
85+ 'ordinal' : self .ordinal ,
86+ }
87+ client = self .root_file .project
88+ endpoint = f"/api/v1/project/{ self .root_file .project .project_string_id } /file/{ self .id } /update-metadata"
89+
90+ response = client .session .put (
91+ client .host + endpoint ,
92+ json = payload )
93+
94+ client .handle_errors (response )
95+
96+ data = response .json ()
97+ new_file_data = data ['file' ]
98+
99+ self .refresh_from_data_dict (data = new_file_data )
100+ return self
64101
65102 def set_ordinal (self , value : int ):
66103 self .ordinal = value
@@ -69,23 +106,57 @@ def set_ordinal(self, value: int):
69106class CompoundFile :
70107 project : Project
71108 parent_file_data : dict
72- child_files_to_upload : List [CompoundChildFile ]
109+ child_files : List [CompoundChildFile ]
73110
74111 def __init__ (self , project : Project , name : str , directory_id : int ):
75112 self .project = project
76113 self .name = name
77114 self .directory_id = directory_id
78- self .child_files_to_upload = []
115+ self .child_files = []
116+
117+ @staticmethod
118+ def from_dict (project : Project , dir_id : int , dict_data : dict ):
119+ result = CompoundFile (project = project , name = dict_data .get ('original_filename' ), directory_id = dir_id )
120+ result .__refresh_compound_file_from_data_dict (data = dict_data )
121+ child_files = result .__fetch_child_files ()
122+ result .child_files = child_files
123+ return result
124+
125+ def __fetch_child_files (self ) -> List [CompoundChildFile ]:
126+ client = self .project
127+ endpoint = f"/api/v1/project/{ self .project .project_string_id } /file/{ self .id } /child-files"
128+
129+ response = client .session .get (client .host + endpoint )
130+
131+ client .handle_errors (response )
132+
133+ data = response .json ()
134+ child_files_data = data ['child_files' ]
135+ result = []
136+ for elm in child_files_data :
137+ child_file = CompoundChildFile (root_file = self , child_file_type = elm .get ('type' ))
138+ child_file .refresh_from_data_dict (data = elm )
139+ result .append (child_file )
140+ return result
141+
142+ def update_all (self ) -> bool :
143+ """
144+ Syncs parent and child metadata with backend API.
145+ :return: True/False
146+ """
147+ for child in self .child_files :
148+ child .update ()
149+ return True
79150
80151 def __refresh_compound_file_from_data_dict (self , data : dict ):
81152 if not data :
82153 return
83154 for key in data :
84155 setattr (self , key , data [key ])
85156
86- def remove_compound_file (self , child_file : CompoundChildFile ) -> List [CompoundChildFile ]:
87- self .child_files_to_upload .remove (child_file )
88- return self .child_files_to_upload
157+ def remove_child_file (self , child_file : CompoundChildFile ) -> List [CompoundChildFile ]:
158+ self .child_files .remove (child_file )
159+ return self .child_files
89160
90161 def __create_compound_parent_file (self ):
91162 url = f'/api/v1/project/{ self .project .project_string_id } /file/new-compound'
@@ -110,7 +181,8 @@ def __create_child_file(self, child_file: CompoundChildFile):
110181 frame_packet_map = child_file .frame_packet_map ,
111182 assume_new_instances_machine_made = child_file .assume_new_instances_machine_made ,
112183 convert_names_to_label_files = child_file .convert_names_to_label_files ,
113- parent_file_id = self .parent_file_data .get ('id' )
184+ parent_file_id = self .parent_file_data .get ('id' ),
185+ ordinal = child_file .ordinal ,
114186 )
115187 elif child_file .child_file_type == 'from_url' :
116188 return self .project .file .from_url (
@@ -121,7 +193,8 @@ def __create_child_file(self, child_file: CompoundChildFile):
121193 video_split_duration = child_file .video_split_duration ,
122194 instance_list = child_file .instance_list ,
123195 frame_packet_map = child_file .frame_packet_map ,
124- parent_file_id = self .parent_file_data .get ('id' )
196+ parent_file_id = self .parent_file_data .get ('id' ),
197+ ordinal = child_file .ordinal ,
125198 )
126199 elif child_file .child_file_type == 'from_blob_path' :
127200 return self .project .file .from_blob_path (
@@ -132,7 +205,8 @@ def __create_child_file(self, child_file: CompoundChildFile):
132205 instance_list = child_file .instance_list ,
133206 file_name = child_file .file_name ,
134207 frame_packet_map = child_file .frame_packet_map ,
135- parent_file_id = self .parent_file_data .get ('id' )
208+ parent_file_id = self .parent_file_data .get ('id' ),
209+ ordinal = child_file .ordinal ,
136210 )
137211
138212 def add_child_from_local (self ,
@@ -141,17 +215,21 @@ def add_child_from_local(self,
141215 frame_packet_map : dict = None ,
142216 assume_new_instances_machine_made : bool = True ,
143217 convert_names_to_label_files : bool = True ,
144- ordinal : int = 0 ):
218+ ordinal : int = None ):
219+ if ordinal is None :
220+ ordinal = len (self .child_files )
145221 new_child_file = CompoundChildFile (
222+ root_file = self ,
146223 child_file_type = "from_local" ,
147224 path = path ,
148225 directory_id = self .directory_id ,
149226 instance_list = instance_list ,
150227 frame_packet_map = frame_packet_map ,
151228 assume_new_instances_machine_made = assume_new_instances_machine_made ,
152- convert_names_to_label_files = convert_names_to_label_files
229+ convert_names_to_label_files = convert_names_to_label_files ,
230+ ordinal = ordinal
153231 )
154- self .child_files_to_upload .append (new_child_file )
232+ self .child_files .append (new_child_file )
155233 return new_child_file
156234
157235 def add_child_file_from_url (self ,
@@ -162,8 +240,11 @@ def add_child_file_from_url(self,
162240 video_split_duration : int = None ,
163241 instance_list : list = None ,
164242 frame_packet_map : dict = None ,
165- ordinal : int = 0 ):
243+ ordinal : int = None ):
244+ if ordinal is None :
245+ ordinal = len (self .child_files )
166246 new_child_file = CompoundChildFile (
247+ root_file = self ,
167248 child_file_type = "from_url" ,
168249 url = url ,
169250 media_type = media_type ,
@@ -173,8 +254,9 @@ def add_child_file_from_url(self,
173254 video_split_duration = video_split_duration ,
174255 instance_list = instance_list ,
175256 frame_packet_map = frame_packet_map ,
257+ ordinal = ordinal
176258 )
177- self .child_files_to_upload .append (new_child_file )
259+ self .child_files .append (new_child_file )
178260 return new_child_file
179261
180262 def add_child_from_blob_path (self ,
@@ -185,9 +267,12 @@ def add_child_from_blob_path(self,
185267 instance_list : list = None ,
186268 file_name : str = None ,
187269 frame_packet_map : dict = None ,
188- ordinal : int = 0
270+ ordinal : int = None
189271 ):
272+ if ordinal is None :
273+ ordinal = len (self .child_files )
190274 new_child_file = CompoundChildFile (
275+ root_file = self ,
191276 child_file_type = "from_blob_path" ,
192277 blob_path = blob_path ,
193278 bucket_name = bucket_name ,
@@ -197,15 +282,16 @@ def add_child_from_blob_path(self,
197282 instance_list = instance_list ,
198283 file_name = file_name ,
199284 frame_packet_map = frame_packet_map ,
285+ ordinal = ordinal
200286 )
201- self .child_files_to_upload .append (new_child_file )
287+ self .child_files .append (new_child_file )
202288 return new_child_file
203289
204290 def upload (self ):
205- if len (self .child_files_to_upload ) == 0 :
291+ if len (self .child_files ) == 0 :
206292 raise AssertionError ('Need to add at least one child file to the compound file before calling upload()' )
207293 parent_file_data : dict = self .__create_compound_parent_file ()
208294
209- for child_file in self .child_files_to_upload :
295+ for child_file in self .child_files :
210296 self .__create_child_file (child_file )
211297 return parent_file_data
0 commit comments