11"""Test utilities and helpers for Nutrient DWS Python Client tests."""
2+
23from datetime import datetime , timezone
34import json
45from typing import Any , Optional , TypedDict , Literal , List
56from pathlib import Path
67
8+
79class XfdfAnnotation (TypedDict ):
8- type : Literal [' highlight' , ' text' , ' square' , ' circle' ]
10+ type : Literal [" highlight" , " text" , " square" , " circle" ]
911 page : int
1012 rect : List [int ]
1113 content : Optional [str ]
1214 color : Optional [str ]
1315
16+
1417class TestDocumentGenerator :
1518 """Generate test documents and content for testing purposes."""
1619
@@ -65,10 +68,17 @@ def generate_pdf_with_table() -> bytes:
6568 return TestDocumentGenerator .generate_simple_pdf_content (content )
6669
6770 @staticmethod
68- def generate_html_content (title : str = "Test Document" , include_styles : bool = True , include_table : bool = False , include_images : bool = False , include_form : bool = False ) -> bytes :
71+ def generate_html_content (
72+ title : str = "Test Document" ,
73+ include_styles : bool = True ,
74+ include_table : bool = False ,
75+ include_images : bool = False ,
76+ include_form : bool = False ,
77+ ) -> bytes :
6978 """Generate HTML content for testing."""
7079
71- styles = """<style>
80+ styles = (
81+ """<style>
7282body {
7383 font-family: Arial, sans-serif;
7484 margin: 40px;
@@ -110,8 +120,12 @@ def generate_html_content(title: str = "Test Document", include_styles: bool = T
110120 border: 1px solid #ddd;
111121 border-radius: 4px;
112122}
113- </style>""" if include_styles else ""
114- tables = """<h2>Data Table</h2>
123+ </style>"""
124+ if include_styles
125+ else ""
126+ )
127+ tables = (
128+ """<h2>Data Table</h2>
115129<table>
116130 <thead>
117131 <tr>
@@ -141,13 +155,21 @@ def generate_html_content(title: str = "Test Document", include_styles: bool = T
141155 <td>$40.00</td>
142156 </tr>
143157 </tbody>
144- </table>""" if include_table else ""
145- images = """<h2>Images</h2>
158+ </table>"""
159+ if include_table
160+ else ""
161+ )
162+ images = (
163+ """<h2>Images</h2>
146164<p>Below is a placeholder for image content:</p>
147165<div style="width: 200px; height: 200px; background-color: #e0e0e0; display: flex; align-items: center; justify-content: center; margin: 20px 0;">
148166 <span style="color: #666;">Image Placeholder</span>
149- </div>""" if include_images else ""
150- form = """<h2>Form Example</h2>
167+ </div>"""
168+ if include_images
169+ else ""
170+ )
171+ form = (
172+ """<h2>Form Example</h2>
151173<form>
152174 <div class="form-group">
153175 <label for="name">Name:</label>
@@ -161,7 +183,10 @@ def generate_html_content(title: str = "Test Document", include_styles: bool = T
161183 <label for="message">Message:</label>
162184 <textarea id="message" name="message" rows="4" placeholder="Enter your message"></textarea>
163185 </div>
164- </form>""" if include_form else ""
186+ </form>"""
187+ if include_form
188+ else ""
189+ )
165190
166191 html = f"""<!DOCTYPE html>
167192<html lang="en">
@@ -180,17 +205,19 @@ def generate_html_content(title: str = "Test Document", include_styles: bool = T
180205 return html .encode ("utf-8" )
181206
182207 @staticmethod
183- def generate_xfdf_content (annotations : Optional [list [XfdfAnnotation ]] = None ) -> bytes :
208+ def generate_xfdf_content (
209+ annotations : Optional [list [XfdfAnnotation ]] = None ,
210+ ) -> bytes :
184211 """Generate XFDF annotation content."""
185212
186213 if annotations is None :
187214 annotations = [
188215 {
189- "type" : ' highlight' ,
216+ "type" : " highlight" ,
190217 "page" : 0 ,
191218 "rect" : [100 , 100 , 200 , 150 ],
192- "color" : ' #FFFF00' ,
193- "content" : ' Important text' ,
219+ "color" : " #FFFF00" ,
220+ "content" : " Important text" ,
194221 },
195222 ]
196223
@@ -201,11 +228,11 @@ def generate_xfdf_content(annotations: Optional[list[XfdfAnnotation]] = None) ->
201228 color = annot ["color" ] or "#FFFF00"
202229 if annot ["type" ] == "highlight" :
203230 inner_xfdf = f"""<highlight page="${ annot ["page" ]} " rect="${ rectStr } " color="${ color } ">
204- <contents>${ annot .get ("content" , ' Highlighted text' )} </contents>
231+ <contents>${ annot .get ("content" , " Highlighted text" )} </contents>
205232 </highlight>"""
206233 elif annot ["type" ] == "text" :
207234 inner_xfdf = f"""<text page="${ annot ["page" ]} " rect="${ rectStr } " color="${ color } ">
208- <contents>${ annot .get ("content" , ' Note' )} </contents>
235+ <contents>${ annot .get ("content" , " Note" )} </contents>
209236 </text>"""
210237 elif annot ["type" ] == "square" :
211238 inner_xfdf = f"""<square page="{ annot ["page" ]} " rect="{ rectStr } " color="{ color } " />"""
@@ -224,17 +251,19 @@ def generate_xfdf_content(annotations: Optional[list[XfdfAnnotation]] = None) ->
224251 @staticmethod
225252 def generate_instant_json_content (annotations : Optional [list ] = None ) -> bytes :
226253 """Generate Instant JSON annotation content."""
227- annotations = annotations or [{
228- "v" : 2 ,
229- "type" : 'pspdfkit/text' ,
230- "pageIndex" : 0 ,
231- "bbox" : [100 , 100 , 200 , 150 ],
232- "content" : 'Test annotation' ,
233- "fontSize" : 14 ,
234- "opacity" : 1 ,
235- "horizontalAlign" : 'left' ,
236- "verticalAlign" : 'top' ,
237- }]
254+ annotations = annotations or [
255+ {
256+ "v" : 2 ,
257+ "type" : "pspdfkit/text" ,
258+ "pageIndex" : 0 ,
259+ "bbox" : [100 , 100 , 200 , 150 ],
260+ "content" : "Test annotation" ,
261+ "fontSize" : 14 ,
262+ "opacity" : 1 ,
263+ "horizontalAlign" : "left" ,
264+ "verticalAlign" : "top" ,
265+ }
266+ ]
238267 instant_data = {
239268 "format" : "https://pspdfkit.com/instant-json/v1" ,
240269 "annotations" : [],
@@ -282,7 +311,7 @@ def validate_pdf_output(result: Any) -> None:
282311
283312 @staticmethod
284313 def validate_office_output (
285- result : Any , format : Literal ["docx" , "xlsx" , "pptx" ]
314+ result : Any , format : Literal ["docx" , "xlsx" , "pptx" ]
286315 ) -> None :
287316 """Validates Office document output"""
288317 mime_types = {
@@ -291,7 +320,11 @@ def validate_office_output(
291320 "pptx" : "application/vnd.openxmlformats-officedocument.presentationml.presentation" ,
292321 }
293322
294- if not isinstance (result , dict ) or not result .get ("success" ) or "output" not in result :
323+ if (
324+ not isinstance (result , dict )
325+ or not result .get ("success" )
326+ or "output" not in result
327+ ):
295328 raise ValueError ("Result must be successful with output" )
296329
297330 output = result ["output" ]
@@ -307,7 +340,11 @@ def validate_image_output(
307340 result : Any , format : Literal ["png" , "jpeg" , "jpg" , "webp" ] | None = None
308341 ) -> None :
309342 """Validates image output"""
310- if not isinstance (result , dict ) or not result .get ("success" ) or "output" not in result :
343+ if (
344+ not isinstance (result , dict )
345+ or not result .get ("success" )
346+ or "output" not in result
347+ ):
311348 raise ValueError ("Result must be successful with output" )
312349
313350 output = result ["output" ]
@@ -325,15 +362,23 @@ def validate_image_output(
325362 }
326363 valid_mimes = format_mime_types .get (format , [f"image/{ format } " ])
327364 if output .get ("mimeType" ) not in valid_mimes :
328- raise ValueError (f"Expected format { format } , got { output .get ('mimeType' )} " )
365+ raise ValueError (
366+ f"Expected format { format } , got { output .get ('mimeType' )} "
367+ )
329368 else :
330- if not isinstance (output .get ("mimeType" ), str ) or not output ["mimeType" ].startswith ("image/" ):
369+ if not isinstance (output .get ("mimeType" ), str ) or not output [
370+ "mimeType"
371+ ].startswith ("image/" ):
331372 raise ValueError ("Expected image MIME type" )
332373
333374 @staticmethod
334375 def validate_json_output (result : Any ) -> None :
335376 """Validates JSON extraction output"""
336- if not isinstance (result , dict ) or not result .get ("success" ) or "output" not in result :
377+ if (
378+ not isinstance (result , dict )
379+ or not result .get ("success" )
380+ or "output" not in result
381+ ):
337382 raise ValueError ("Result must be successful with output" )
338383
339384 output = result ["output" ]
@@ -343,7 +388,9 @@ def validate_json_output(result: Any) -> None:
343388 raise ValueError ("Output data must be an object" )
344389
345390 @staticmethod
346- def validate_error_response (result : Any , expected_error_type : str | None = None ) -> None :
391+ def validate_error_response (
392+ result : Any , expected_error_type : str | None = None
393+ ) -> None :
347394 """Validates error response"""
348395 if not isinstance (result , dict ):
349396 raise ValueError ("Result must be a dictionary" )
0 commit comments