22import time
33
44import ayon_api
5- from ayon_api import TransferProgress
6- from ayon_api .server_api import RequestTypes
75import pyblish .api
86
97from ayon_core .lib import get_media_mime_type , format_file_size
108from ayon_core .pipeline .publish import (
119 PublishXmlValidationError ,
1210 get_publish_repre_path ,
1311)
14- import requests .exceptions
1512
1613
1714class IntegrateAYONReview (pyblish .api .InstancePlugin ):
@@ -34,15 +31,6 @@ def process(self, instance):
3431 self ._upload_reviewable (project_name , version_id , instance )
3532
3633 def _upload_reviewable (self , project_name , version_id , instance ):
37- ayon_con = ayon_api .get_server_api_connection ()
38- major , minor , _ , _ , _ = ayon_con .get_server_version_tuple ()
39- if (major , minor ) < (1 , 3 ):
40- self .log .info (
41- "Skipping reviewable upload, supported from server 1.3.x."
42- f" Current server version { ayon_con .get_server_version ()} "
43- )
44- return
45-
4634 uploaded_labels = set ()
4735 for repre in instance .data ["representations" ]:
4836 repre_tags = repre .get ("tags" ) or []
@@ -73,22 +61,40 @@ def _upload_reviewable(self, project_name, version_id, instance):
7361 continue
7462
7563 label = self ._get_review_label (repre , uploaded_labels )
76- query = ""
77- if label :
78- query = f"?label={ label } "
7964
80- endpoint = (
81- f"/projects/{ project_name } "
82- f"/versions/{ version_id } /reviewables{ query } "
83- )
84- self .log .info (f"Uploading reviewable { repre_path } " )
85- # Upload with retries and clear help if it keeps failing
86- self ._upload_with_retries (
87- ayon_con ,
88- endpoint ,
89- repre_path ,
90- content_type ,
65+ size = os .path .getsize (repre_path )
66+ start = time .time ()
67+ self .log .info (
68+ f"Uploading '{ repre_path } ' (size: { format_file_size (size )} )"
9169 )
70+ try :
71+ ayon_api .upload_reviewable (
72+ project_name ,
73+ version_id ,
74+ repre_path ,
75+ content_type = content_type ,
76+ label = label ,
77+ # Pass headers to fix bug in ayon-api (fixed in 1.2.15)
78+ headers = {},
79+ )
80+ except Exception as exc :
81+ self .log .warning (
82+ f"Review upload failed after { time .time () - start } s." ,
83+ exc_info = True ,
84+ )
85+ raise PublishXmlValidationError (
86+ self ,
87+ (
88+ "Upload of reviewable timed out or failed after"
89+ " multiple attempts. Please try publishing again."
90+ ),
91+ formatting_data = {
92+ "upload_type" : "Review" ,
93+ "file" : repre_path ,
94+ "error" : str (exc ),
95+ },
96+ help_filename = "upload_file.xml" ,
97+ )
9298
9399 def _get_review_label (self , repre , uploaded_labels ):
94100 # Use output name as label if available
@@ -101,74 +107,3 @@ def _get_review_label(self, repre, uploaded_labels):
101107 idx += 1
102108 label = f"{ orig_label } _{ idx } "
103109 return label
104-
105- def _upload_with_retries (
106- self ,
107- ayon_con : ayon_api .ServerAPI ,
108- endpoint : str ,
109- repre_path : str ,
110- content_type : str ,
111- ):
112- """Upload file with simple retries."""
113- filename = os .path .basename (repre_path )
114-
115- headers = ayon_con .get_headers (content_type )
116- headers ["x-file-name" ] = filename
117- max_retries = ayon_con .get_default_max_retries ()
118- # Retries are already implemented in 'ayon_api.upload_file'
119- # - added in ayon api 1.2.7
120- if hasattr (TransferProgress , "get_attempt" ):
121- max_retries = 1
122-
123- size = os .path .getsize (repre_path )
124- self .log .info (
125- f"Uploading '{ repre_path } ' (size: { format_file_size (size )} )"
126- )
127-
128- # How long to sleep before next attempt
129- wait_time = 1
130- last_error = None
131- for attempt in range (max_retries ):
132- attempt += 1
133- start = time .time ()
134- try :
135- output = ayon_con .upload_file (
136- endpoint ,
137- repre_path ,
138- headers = headers ,
139- request_type = RequestTypes .post ,
140- )
141- self .log .debug (f"Uploaded in { time .time () - start } s." )
142- return output
143-
144- except (
145- requests .exceptions .Timeout ,
146- requests .exceptions .ConnectionError
147- ) as exc :
148- # Log and retry with backoff if attempts remain
149- if attempt >= max_retries :
150- last_error = exc
151- break
152-
153- self .log .warning (
154- f"Review upload failed ({ attempt } /{ max_retries } )"
155- f" after { time .time () - start } s."
156- f" Retrying in { wait_time } s..." ,
157- exc_info = True ,
158- )
159- time .sleep (wait_time )
160-
161- # Exhausted retries - raise a user-friendly validation error with help
162- raise PublishXmlValidationError (
163- self ,
164- (
165- "Upload of reviewable timed out or failed after multiple"
166- " attempts. Please try publishing again."
167- ),
168- formatting_data = {
169- "upload_type" : "Review" ,
170- "file" : repre_path ,
171- "error" : str (last_error ),
172- },
173- help_filename = "upload_file.xml" ,
174- )
0 commit comments