@@ -226,6 +226,81 @@ def handler(request: httpx.Request) -> httpx.Response:
226226 assert timeout_value == pytest .approx (0.31 )
227227
228228
229+ def test_watermark_pdf_with_image_request_customization (
230+ monkeypatch : pytest .MonkeyPatch ,
231+ ) -> None :
232+ monkeypatch .delenv ("PDFREST_API_KEY" , raising = False )
233+ input_file = make_pdf_file (PdfRestFileID .generate (1 ))
234+ watermark_file = make_pdf_file (PdfRestFileID .generate (1 ), name = "sync-stamp.pdf" )
235+ output_id = str (PdfRestFileID .generate ())
236+ captured_timeout : dict [str , float | dict [str , float ] | None ] = {}
237+
238+ def handler (request : httpx .Request ) -> httpx .Response :
239+ if request .method == "POST" and request .url .path == "/watermarked-pdf" :
240+ assert request .url .params ["trace" ] == "img-sync"
241+ assert request .headers ["X-Debug" ] == "img-sync"
242+ captured_timeout ["value" ] = request .extensions .get ("timeout" )
243+ payload = json .loads (request .content .decode ("utf-8" ))
244+ assert payload ["watermark_file_id" ] == str (watermark_file .id )
245+ assert payload ["watermark_file_scale" ] == pytest .approx (0.65 )
246+ assert payload ["horizontal_alignment" ] == "left"
247+ assert payload ["vertical_alignment" ] == "top"
248+ assert payload ["x" ] == - 24
249+ assert payload ["y" ] == 48
250+ assert payload ["rotation" ] == 15
251+ assert payload ["debug" ] == "img-sync"
252+ assert payload ["id" ] == str (input_file .id )
253+ return httpx .Response (
254+ 200 ,
255+ json = {
256+ "inputId" : [input_file .id , watermark_file .id ],
257+ "outputId" : [output_id ],
258+ },
259+ )
260+ if request .method == "GET" and request .url .path == f"/resource/{ output_id } " :
261+ assert request .url .params ["format" ] == "info"
262+ assert request .url .params ["trace" ] == "img-sync"
263+ assert request .headers ["X-Debug" ] == "img-sync"
264+ return httpx .Response (
265+ 200 ,
266+ json = build_file_info_payload (
267+ output_id ,
268+ "img-sync.pdf" ,
269+ "application/pdf" ,
270+ ),
271+ )
272+ msg = f"Unexpected request { request .method } { request .url } "
273+ raise AssertionError (msg )
274+
275+ transport = httpx .MockTransport (handler )
276+ with PdfRestClient (api_key = VALID_API_KEY , transport = transport ) as client :
277+ response = client .watermark_pdf_with_image (
278+ input_file ,
279+ watermark_file = watermark_file ,
280+ watermark_file_scale = 0.65 ,
281+ horizontal_alignment = "left" ,
282+ vertical_alignment = "top" ,
283+ x = - 24 ,
284+ y = 48 ,
285+ rotation = 15 ,
286+ extra_query = {"trace" : "img-sync" },
287+ extra_headers = {"X-Debug" : "img-sync" },
288+ extra_body = {"debug" : "img-sync" },
289+ timeout = 0.57 ,
290+ )
291+
292+ assert isinstance (response , PdfRestFileBasedResponse )
293+ assert response .output_file .name == "img-sync.pdf"
294+ timeout_value = captured_timeout ["value" ]
295+ assert timeout_value is not None
296+ if isinstance (timeout_value , dict ):
297+ assert all (
298+ component == pytest .approx (0.57 ) for component in timeout_value .values ()
299+ )
300+ else :
301+ assert timeout_value == pytest .approx (0.57 )
302+
303+
229304def test_watermark_pdf_with_text_validation_rejects_invalid_text_color (
230305 monkeypatch : pytest .MonkeyPatch ,
231306) -> None :
@@ -303,6 +378,49 @@ def test_watermark_pdf_with_image_validation_rejects_non_pdf_watermark(
303378 client .watermark_pdf_with_image (input_file , watermark_file = bad_watermark )
304379
305380
381+ def test_watermark_pdf_with_text_validation_rejects_multiple_input_files (
382+ monkeypatch : pytest .MonkeyPatch ,
383+ ) -> None :
384+ monkeypatch .delenv ("PDFREST_API_KEY" , raising = False )
385+ input_file_one = make_pdf_file (PdfRestFileID .generate (1 ))
386+ input_file_two = make_pdf_file (PdfRestFileID .generate (1 ), name = "second.pdf" )
387+ with (
388+ PdfRestClient (
389+ api_key = VALID_API_KEY ,
390+ transport = httpx .MockTransport (
391+ lambda _ : (_ for _ in ()).throw (RuntimeError ("Should not be called" ))
392+ ),
393+ ) as client ,
394+ pytest .raises (ValidationError , match = "at most 1 item" ),
395+ ):
396+ client .watermark_pdf_with_text (
397+ [input_file_one , input_file_two ],
398+ watermark_text = "TooManyInputs" ,
399+ )
400+
401+
402+ def test_watermark_pdf_with_image_validation_rejects_multiple_watermark_files (
403+ monkeypatch : pytest .MonkeyPatch ,
404+ ) -> None :
405+ monkeypatch .delenv ("PDFREST_API_KEY" , raising = False )
406+ input_file = make_pdf_file (PdfRestFileID .generate (1 ))
407+ watermark_file_one = make_pdf_file (PdfRestFileID .generate (1 ), name = "first.pdf" )
408+ watermark_file_two = make_pdf_file (PdfRestFileID .generate (1 ), name = "second.pdf" )
409+ with (
410+ PdfRestClient (
411+ api_key = VALID_API_KEY ,
412+ transport = httpx .MockTransport (
413+ lambda _ : (_ for _ in ()).throw (RuntimeError ("Should not be called" ))
414+ ),
415+ ) as client ,
416+ pytest .raises (ValidationError , match = "at most 1 item" ),
417+ ):
418+ client .watermark_pdf_with_image (
419+ input_file ,
420+ watermark_file = [watermark_file_one , watermark_file_two ],
421+ )
422+
423+
306424def test_watermark_pdf_with_text_validation_rejects_short_text_size (
307425 monkeypatch : pytest .MonkeyPatch ,
308426) -> None :
@@ -526,3 +644,118 @@ def handler(request: httpx.Request) -> httpx.Response:
526644 )
527645 else :
528646 assert timeout_value == pytest .approx (0.42 )
647+
648+
649+ @pytest .mark .asyncio
650+ async def test_async_watermark_pdf_with_image_request_customization (
651+ monkeypatch : pytest .MonkeyPatch ,
652+ ) -> None :
653+ monkeypatch .delenv ("PDFREST_API_KEY" , raising = False )
654+ input_file = make_pdf_file (PdfRestFileID .generate (2 ))
655+ watermark_file = make_pdf_file (PdfRestFileID .generate (2 ), name = "async-stamp.pdf" )
656+ output_id = str (PdfRestFileID .generate ())
657+ captured_timeout : dict [str , float | dict [str , float ] | None ] = {}
658+
659+ def handler (request : httpx .Request ) -> httpx .Response :
660+ if request .method == "POST" and request .url .path == "/watermarked-pdf" :
661+ assert request .url .params ["trace" ] == "img-async"
662+ assert request .headers ["X-Debug" ] == "img-async"
663+ captured_timeout ["value" ] = request .extensions .get ("timeout" )
664+ payload = json .loads (request .content .decode ("utf-8" ))
665+ assert payload ["watermark_file_id" ] == str (watermark_file .id )
666+ assert payload ["watermark_file_scale" ] == pytest .approx (0.25 )
667+ assert payload ["opacity" ] == pytest .approx (0.85 )
668+ assert payload ["horizontal_alignment" ] == "right"
669+ assert payload ["vertical_alignment" ] == "bottom"
670+ assert payload ["x" ] == 12
671+ assert payload ["y" ] == - 18
672+ assert payload ["rotation" ] == 330
673+ assert payload ["debug" ] == "img-async"
674+ assert payload ["id" ] == str (input_file .id )
675+ return httpx .Response (
676+ 200 ,
677+ json = {
678+ "inputId" : [input_file .id , watermark_file .id ],
679+ "outputId" : [output_id ],
680+ },
681+ )
682+ if request .method == "GET" and request .url .path == f"/resource/{ output_id } " :
683+ assert request .url .params ["format" ] == "info"
684+ assert request .url .params ["trace" ] == "img-async"
685+ assert request .headers ["X-Debug" ] == "img-async"
686+ return httpx .Response (
687+ 200 ,
688+ json = build_file_info_payload (
689+ output_id ,
690+ "img-async.pdf" ,
691+ "application/pdf" ,
692+ ),
693+ )
694+ msg = f"Unexpected request { request .method } { request .url } "
695+ raise AssertionError (msg )
696+
697+ transport = httpx .MockTransport (handler )
698+ async with AsyncPdfRestClient (api_key = ASYNC_API_KEY , transport = transport ) as client :
699+ response = await client .watermark_pdf_with_image (
700+ input_file ,
701+ watermark_file = watermark_file ,
702+ watermark_file_scale = 0.25 ,
703+ opacity = 0.85 ,
704+ horizontal_alignment = "right" ,
705+ vertical_alignment = "bottom" ,
706+ x = 12 ,
707+ y = - 18 ,
708+ rotation = 330 ,
709+ extra_query = {"trace" : "img-async" },
710+ extra_headers = {"X-Debug" : "img-async" },
711+ extra_body = {"debug" : "img-async" },
712+ timeout = 0.29 ,
713+ )
714+
715+ assert isinstance (response , PdfRestFileBasedResponse )
716+ assert response .output_file .name == "img-async.pdf"
717+ timeout_value = captured_timeout ["value" ]
718+ assert timeout_value is not None
719+ if isinstance (timeout_value , dict ):
720+ assert all (
721+ component == pytest .approx (0.29 ) for component in timeout_value .values ()
722+ )
723+ else :
724+ assert timeout_value == pytest .approx (0.29 )
725+
726+
727+ @pytest .mark .asyncio
728+ async def test_async_watermark_pdf_with_text_validation_rejects_multiple_input_files (
729+ monkeypatch : pytest .MonkeyPatch ,
730+ ) -> None :
731+ monkeypatch .delenv ("PDFREST_API_KEY" , raising = False )
732+ input_file_one = make_pdf_file (PdfRestFileID .generate (2 ))
733+ input_file_two = make_pdf_file (PdfRestFileID .generate (2 ), name = "second.pdf" )
734+ transport = httpx .MockTransport (
735+ lambda _ : (_ for _ in ()).throw (RuntimeError ("Should not be called" ))
736+ )
737+ async with AsyncPdfRestClient (api_key = ASYNC_API_KEY , transport = transport ) as client :
738+ with pytest .raises (ValidationError , match = "at most 1 item" ):
739+ await client .watermark_pdf_with_text (
740+ [input_file_one , input_file_two ],
741+ watermark_text = "TooManyInputs" ,
742+ )
743+
744+
745+ @pytest .mark .asyncio
746+ async def test_async_watermark_pdf_with_image_validation_rejects_multiple_watermark_files (
747+ monkeypatch : pytest .MonkeyPatch ,
748+ ) -> None :
749+ monkeypatch .delenv ("PDFREST_API_KEY" , raising = False )
750+ input_file = make_pdf_file (PdfRestFileID .generate (2 ))
751+ watermark_file_one = make_pdf_file (PdfRestFileID .generate (2 ), name = "first.pdf" )
752+ watermark_file_two = make_pdf_file (PdfRestFileID .generate (2 ), name = "second.pdf" )
753+ transport = httpx .MockTransport (
754+ lambda _ : (_ for _ in ()).throw (RuntimeError ("Should not be called" ))
755+ )
756+ async with AsyncPdfRestClient (api_key = ASYNC_API_KEY , transport = transport ) as client :
757+ with pytest .raises (ValidationError , match = "at most 1 item" ):
758+ await client .watermark_pdf_with_image (
759+ input_file ,
760+ watermark_file = [watermark_file_one , watermark_file_two ],
761+ )
0 commit comments