port-ocean 0.28.17__py3-none-any.whl → 0.28.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of port-ocean might be problematic. Click here for more details.

@@ -1,11 +1,20 @@
1
- from contextlib import contextmanager
2
- from typing import Awaitable, Generator, Callable, cast
3
-
4
- from loguru import logger
5
1
  import asyncio
2
+ import json
6
3
  import multiprocessing
4
+ import os
7
5
  import re
8
- import json
6
+ import shutil
7
+ import stat
8
+ import subprocess
9
+ import tempfile
10
+ from contextlib import contextmanager
11
+ from typing import Any, AsyncGenerator, Awaitable, Callable, Generator, cast
12
+
13
+ import ijson
14
+ from loguru import logger
15
+
16
+ from port_ocean.clients.port.utils import _http_client as _port_http_client
17
+ from port_ocean.context.ocean import ocean
9
18
  from port_ocean.core.handlers.entity_processor.jq_entity_processor import JQEntityProcessor
10
19
  from port_ocean.core.ocean_types import (
11
20
  ASYNC_GENERATOR_RESYNC_TYPE,
@@ -19,16 +28,8 @@ from port_ocean.exceptions.core import (
19
28
  OceanAbortException,
20
29
  KindNotImplementedException,
21
30
  )
22
- import os
23
- from port_ocean.utils.async_http import _http_client
24
- from port_ocean.clients.port.utils import _http_client as _port_http_client
25
31
  from port_ocean.helpers.metric.metric import MetricType, MetricPhase
26
- from port_ocean.context.ocean import ocean
27
- import subprocess
28
- import tempfile
29
- import stat
30
- import ijson
31
- from typing import Any, AsyncGenerator
32
+ from port_ocean.utils.async_http import _http_client
32
33
 
33
34
  def _process_path_type_items(
34
35
  result: RAW_RESULT, items_to_parse: str | None = None
@@ -216,7 +217,9 @@ async def get_items_to_parse_bulks(raw_data: dict[Any, Any], data_path: str, ite
216
217
  | map({{{items_to_parse_name}: ., {base_jq_object_string}}})"""
217
218
 
218
219
  # Use subprocess with list arguments instead of shell=True
219
- jq_args = ["/bin/jq", jq_expression, data_path]
220
+
221
+ jq_path = shutil.which("jq") or "/bin/jq"
222
+ jq_args = [jq_path, jq_expression, data_path]
220
223
 
221
224
  with open(temp_output_path, "w") as output_file:
222
225
  result = subprocess.run(
@@ -271,7 +274,7 @@ def get_events_as_a_stream(
271
274
  max_buffer_size_mb: int = 1
272
275
  ) -> Generator[list[dict[str, Any]], None, None]:
273
276
  events = ijson.sendable_list()
274
- coro = ijson.items_coro(events, target_items)
277
+ coro = ijson.items_coro(events, target_items, use_float=True)
275
278
 
276
279
  # Convert MB to bytes for the buffer size
277
280
  buffer_size = max_buffer_size_mb * 1024 * 1024
@@ -257,7 +257,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
257
257
  else:
258
258
  response = await transport.handle_async_request(request)
259
259
 
260
- await self._log_response_size_async(request, response)
260
+ self._log_response_size(request, response)
261
261
 
262
262
  return response
263
263
  except Exception as e:
@@ -345,35 +345,6 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
345
345
  return int(content_length)
346
346
  return None
347
347
 
348
- async def _log_response_size_async(
349
- self, request: httpx.Request, response: httpx.Response
350
- ) -> None:
351
- """Log the size of the response."""
352
- if not self._should_log_response_size(request):
353
- return
354
-
355
- # Try to get content length from headers first
356
- content_length = self._get_content_length(response)
357
- if content_length is not None:
358
- size_info = content_length
359
- else:
360
- # If no Content-Length header, try to get actual content size
361
- try:
362
- content = await response.aread()
363
- actual_size = len(content)
364
- size_info = actual_size
365
- # Restore the cached body so downstream code can still use .json()/.text/.content
366
- response._content = content # httpx convention
367
- except Exception as e:
368
- cast(logging.Logger, self._logger).error(
369
- f"Error getting response size: {e}"
370
- )
371
- return
372
-
373
- cast(logging.Logger, self._logger).info(
374
- f"Response for {request.method} {request.url} - Size: {size_info} bytes"
375
- )
376
-
377
348
  def _log_response_size(
378
349
  self, request: httpx.Request, response: httpx.Response
379
350
  ) -> None:
@@ -381,24 +352,11 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
381
352
  return
382
353
 
383
354
  content_length = self._get_content_length(response)
384
- if content_length is not None:
385
- size_info = content_length
386
- else:
387
- # If no Content-Length header, try to get actual content size
388
- try:
389
- content = response.read()
390
- actual_size = len(content)
391
- size_info = actual_size
392
- # Restore the cached body so downstream code can still use .json()/.text/.content
393
- response._content = content # httpx convention
394
- except Exception as e:
395
- cast(logging.Logger, self._logger).error(
396
- f"Error getting response size: {e}"
397
- )
398
- return
355
+ if content_length is None:
356
+ return
399
357
 
400
358
  cast(logging.Logger, self._logger).info(
401
- f"Response for {request.method} {request.url} - Size: {size_info} bytes"
359
+ f"Response for {request.method} {request.url} - Size: {content_length} bytes"
402
360
  )
403
361
 
404
362
  async def _should_retry_async(self, response: httpx.Response) -> bool:
@@ -61,9 +61,9 @@ def _http_loguru_handler(level: LogLevelType) -> None:
61
61
 
62
62
  http_memory_handler = HTTPMemoryHandler()
63
63
  signal_handler.register(
64
- http_memory_handler.wait_for_lingering_threads, priority=-200
64
+ http_memory_handler.wait_for_lingering_threads, priority=-900
65
65
  )
66
- signal_handler.register(http_memory_handler.flush, priority=-200)
66
+ signal_handler.register(http_memory_handler.flush, priority=-899)
67
67
 
68
68
  queue_listener = QueueListener(queue, http_memory_handler)
69
69
  queue_listener.start()
@@ -1,5 +1,5 @@
1
1
  import pytest
2
- from unittest.mock import Mock, AsyncMock, patch
2
+ from unittest.mock import Mock, patch
3
3
  from http import HTTPStatus
4
4
  import httpx
5
5
 
@@ -417,7 +417,7 @@ class TestResponseSizeLogging:
417
417
 
418
418
  @patch("port_ocean.helpers.retry.cast")
419
419
  def test_log_response_size_without_content_length(self, mock_cast: Mock) -> None:
420
- """Test _log_response_size reads content when no Content-Length header."""
420
+ """Test _log_response_size does nothing when no Content-Length header."""
421
421
  mock_transport = Mock()
422
422
  mock_logger = Mock()
423
423
  mock_cast.return_value = mock_logger
@@ -432,38 +432,14 @@ class TestResponseSizeLogging:
432
432
 
433
433
  mock_response = Mock()
434
434
  mock_response.headers = {}
435
- mock_response.read.return_value = b"test content"
436
435
 
437
436
  transport._log_response_size(mock_request, mock_response)
438
437
 
439
- mock_response.read.assert_called_once()
440
- mock_logger.info.assert_called_once_with(
441
- "Response for POST https://api.example.com/create - Size: 12 bytes"
442
- )
443
-
444
- @patch("port_ocean.helpers.retry.cast")
445
- def test_log_response_size_read_error(self, mock_cast: Mock) -> None:
446
- """Test _log_response_size handles read errors gracefully."""
447
- mock_transport = Mock()
448
- mock_logger = Mock()
449
- mock_cast.return_value = mock_logger
450
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
451
-
452
- mock_request = Mock()
453
- mock_request.method = "GET"
454
- mock_request.url.host = "api.example.com"
455
-
456
- mock_response = Mock()
457
- mock_response.headers = {}
458
- mock_response.read.side_effect = Exception("Read error")
459
-
460
- transport._log_response_size(mock_request, mock_response)
461
-
462
- mock_logger.error.assert_called_once_with(
463
- "Error getting response size: Read error"
464
- )
438
+ mock_response.read.assert_not_called()
465
439
  mock_logger.info.assert_not_called()
466
440
 
441
+ # Read error path removed since _log_response_size no longer reads body
442
+
467
443
  @patch("port_ocean.helpers.retry.cast")
468
444
  def test_log_response_size_skips_when_should_not_log(self, mock_cast: Mock) -> None:
469
445
  """Test _log_response_size skips logging when _should_log_response_size returns False."""
@@ -482,166 +458,6 @@ class TestResponseSizeLogging:
482
458
 
483
459
  mock_logger.info.assert_not_called()
484
460
 
485
- @pytest.mark.asyncio
486
- @patch("port_ocean.helpers.retry.cast")
487
- async def test_log_response_size_async_with_content_length(
488
- self, mock_cast: Mock
489
- ) -> None:
490
- """Test _log_response_size_async logs when Content-Length header is present."""
491
- mock_transport = Mock()
492
- mock_logger = Mock()
493
- mock_cast.return_value = mock_logger
494
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
495
-
496
- mock_request = Mock()
497
- mock_request.method = "GET"
498
- mock_url = Mock()
499
- mock_url.host = "api.example.com"
500
- mock_url.configure_mock(__str__=lambda self: "https://api.example.com/data")
501
- mock_request.url = mock_url
502
-
503
- mock_response = Mock()
504
- mock_response.headers = {"Content-Length": "1024"}
505
-
506
- await transport._log_response_size_async(mock_request, mock_response)
507
-
508
- mock_logger.info.assert_called_once_with(
509
- "Response for GET https://api.example.com/data - Size: 1024 bytes"
510
- )
511
-
512
- @pytest.mark.asyncio
513
- @patch("port_ocean.helpers.retry.cast")
514
- async def test_log_response_size_async_without_content_length(
515
- self, mock_cast: Mock
516
- ) -> None:
517
- """Test _log_response_size_async reads content when no Content-Length header."""
518
- mock_transport = Mock()
519
- mock_logger = Mock()
520
- mock_cast.return_value = mock_logger
521
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
522
-
523
- mock_request = Mock()
524
- mock_request.method = "POST"
525
- mock_url = Mock()
526
- mock_url.host = "api.example.com"
527
- mock_url.configure_mock(__str__=lambda self: "https://api.example.com/create")
528
- mock_request.url = mock_url
529
-
530
- mock_response = Mock()
531
- mock_response.headers = {}
532
- mock_response.aread = AsyncMock(return_value=b"test content")
533
-
534
- await transport._log_response_size_async(mock_request, mock_response)
535
-
536
- mock_response.aread.assert_called_once()
537
- mock_logger.info.assert_called_once_with(
538
- "Response for POST https://api.example.com/create - Size: 12 bytes"
539
- )
540
-
541
- @pytest.mark.asyncio
542
- @patch("port_ocean.helpers.retry.cast")
543
- async def test_log_response_size_async_read_error(self, mock_cast: Mock) -> None:
544
- """Test _log_response_size_async handles read errors gracefully."""
545
- mock_transport = Mock()
546
- mock_logger = Mock()
547
- mock_cast.return_value = mock_logger
548
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
549
-
550
- mock_request = Mock()
551
- mock_request.method = "GET"
552
- mock_request.url.host = "api.example.com"
553
-
554
- mock_response = Mock()
555
- mock_response.headers = {}
556
- mock_response.aread = AsyncMock(side_effect=Exception("Async read error"))
557
-
558
- await transport._log_response_size_async(mock_request, mock_response)
559
-
560
- mock_logger.error.assert_called_once_with(
561
- "Error getting response size: Async read error"
562
- )
563
- mock_logger.info.assert_not_called()
564
-
565
- @pytest.mark.asyncio
566
- @patch("port_ocean.helpers.retry.cast")
567
- async def test_log_response_size_async_skips_when_should_not_log(
568
- self, mock_cast: Mock
569
- ) -> None:
570
- """Test _log_response_size_async skips logging when _should_log_response_size returns False."""
571
- mock_transport = Mock()
572
- mock_logger = Mock()
573
- mock_cast.return_value = mock_logger
574
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
575
-
576
- mock_request = Mock()
577
- mock_request.url.host = "api.getport.io" # This should skip logging
578
-
579
- mock_response = Mock()
580
- mock_response.headers = {"Content-Length": "1024"}
581
-
582
- await transport._log_response_size_async(mock_request, mock_response)
583
-
584
- mock_logger.info.assert_not_called()
585
-
586
- @pytest.mark.asyncio
587
- @patch("port_ocean.helpers.retry.cast")
588
- async def test_log_response_size_async_restores_content(
589
- self, mock_cast: Mock
590
- ) -> None:
591
- """Test _log_response_size_async restores response content after reading."""
592
- mock_transport = Mock()
593
- mock_logger = Mock()
594
- mock_cast.return_value = mock_logger
595
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
596
-
597
- mock_request = Mock()
598
- mock_request.method = "GET"
599
- mock_url = Mock()
600
- mock_url.host = "api.example.com"
601
- mock_url.configure_mock(__str__=lambda self: "https://api.example.com/data")
602
- mock_request.url = mock_url
603
-
604
- test_content = b"test response content"
605
- mock_response = Mock()
606
- mock_response.headers = {}
607
- mock_response.aread = AsyncMock(return_value=test_content)
608
-
609
- await transport._log_response_size_async(mock_request, mock_response)
610
-
611
- # Verify that the content was restored to the response
612
- assert mock_response._content == test_content
613
- mock_logger.info.assert_called_once_with(
614
- "Response for GET https://api.example.com/data - Size: 21 bytes"
615
- )
616
-
617
- @patch("port_ocean.helpers.retry.cast")
618
- def test_log_response_size_restores_content(self, mock_cast: Mock) -> None:
619
- """Test _log_response_size restores response content after reading."""
620
- mock_transport = Mock()
621
- mock_logger = Mock()
622
- mock_cast.return_value = mock_logger
623
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
624
-
625
- mock_request = Mock()
626
- mock_request.method = "GET"
627
- mock_url = Mock()
628
- mock_url.host = "api.example.com"
629
- mock_url.configure_mock(__str__=lambda self: "https://api.example.com/data")
630
- mock_request.url = mock_url
631
-
632
- test_content = b"test response content"
633
- mock_response = Mock()
634
- mock_response.headers = {}
635
- mock_response.read.return_value = test_content
636
-
637
- transport._log_response_size(mock_request, mock_response)
638
-
639
- # Verify that the content was restored to the response
640
- assert mock_response._content == test_content
641
- mock_logger.info.assert_called_once_with(
642
- "Response for GET https://api.example.com/data - Size: 21 bytes"
643
- )
644
-
645
461
 
646
462
  class TestResponseSizeLoggingIntegration:
647
463
  """Integration tests to verify response consumption works after size logging."""
@@ -655,7 +471,7 @@ class TestResponseSizeLoggingIntegration:
655
471
  def test_log_response_size_preserves_json_consumption(
656
472
  self, mock_cast: Mock
657
473
  ) -> None:
658
- """Test that _log_response_size preserves response for .json() consumption."""
474
+ """When no Content-Length, no logging/reading occurs; response usable."""
659
475
  mock_transport = Mock()
660
476
  mock_logger = Mock()
661
477
  mock_cast.return_value = mock_logger
@@ -665,26 +481,16 @@ class TestResponseSizeLoggingIntegration:
665
481
  mock_request.method = "GET"
666
482
  mock_request.url.host = "api.example.com"
667
483
 
668
- # Create a mock response with JSON content
669
- json_content = b'{"message": "test", "data": [1, 2, 3]}'
670
484
  mock_response = Mock()
671
- mock_response.headers = {} # No Content-Length header to force content reading
672
- mock_response.read.return_value = json_content
485
+ mock_response.headers = {}
673
486
  mock_response.json.return_value = {"message": "test", "data": [1, 2, 3]}
674
487
 
675
- # Call the logging function
676
488
  transport._log_response_size(mock_request, mock_response)
677
489
 
678
- # Verify logging occurred
679
- mock_logger.info.assert_called_once()
680
-
681
- # Verify that response.json() can still be called without StreamConsumed error
490
+ mock_logger.info.assert_not_called()
682
491
  result = mock_response.json()
683
492
  assert result == {"message": "test", "data": [1, 2, 3]}
684
-
685
- # Verify that read was called and content was restored
686
- mock_response.read.assert_called_once()
687
- assert mock_response._content == json_content
493
+ mock_response.read.assert_not_called()
688
494
 
689
495
  @patch("port_ocean.helpers.retry.cast")
690
496
  def test_log_response_size_with_content_length_preserves_json(
@@ -718,83 +524,11 @@ class TestResponseSizeLoggingIntegration:
718
524
  # Verify that read was NOT called since we had Content-Length
719
525
  mock_response.read.assert_not_called()
720
526
 
721
- @pytest.mark.asyncio
722
- @patch("port_ocean.helpers.retry.cast")
723
- async def test_log_response_size_async_preserves_json_consumption(
724
- self, mock_cast: Mock
725
- ) -> None:
726
- """Test that _log_response_size_async preserves response for .json() consumption."""
727
- mock_transport = Mock()
728
- mock_logger = Mock()
729
- mock_cast.return_value = mock_logger
730
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
731
-
732
- mock_request = Mock()
733
- mock_request.method = "GET"
734
- mock_request.url.host = "api.example.com"
735
-
736
- # Create a mock response with JSON content
737
- json_content = b'{"users": [{"name": "John", "age": 30}]}'
738
- mock_response = Mock()
739
- mock_response.headers = {} # No Content-Length header to force content reading
740
- mock_response.aread = AsyncMock(return_value=json_content)
741
- mock_response.json.return_value = {"users": [{"name": "John", "age": 30}]}
742
-
743
- # Call the async logging function
744
- await transport._log_response_size_async(mock_request, mock_response)
745
-
746
- # Verify logging occurred
747
- mock_logger.info.assert_called_once()
748
-
749
- # Verify that response.json() can still be called without StreamConsumed error
750
- result = mock_response.json()
751
- assert result == {"users": [{"name": "John", "age": 30}]}
752
-
753
- # Verify that aread was called and content was restored
754
- mock_response.aread.assert_called_once()
755
- assert mock_response._content == json_content
756
-
757
- @pytest.mark.asyncio
758
- @patch("port_ocean.helpers.retry.cast")
759
- async def test_log_response_size_async_with_content_length_preserves_json(
760
- self, mock_cast: Mock
761
- ) -> None:
762
- """Test that _log_response_size_async with Content-Length header preserves JSON consumption."""
763
- mock_transport = Mock()
764
- mock_logger = Mock()
765
- mock_cast.return_value = mock_logger
766
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
767
-
768
- mock_request = Mock()
769
- mock_request.method = "PUT"
770
- mock_request.url.host = "api.example.com"
771
-
772
- # Create a mock response with Content-Length header
773
- mock_response = Mock()
774
- mock_response.headers = {"Content-Length": "2048"}
775
- mock_response.json.return_value = {
776
- "updated": True,
777
- "timestamp": "2023-12-01T12:00:00Z",
778
- }
779
-
780
- # Call the async logging function
781
- await transport._log_response_size_async(mock_request, mock_response)
782
-
783
- # Verify logging occurred
784
- mock_logger.info.assert_called_once()
785
-
786
- # Verify that response.json() can still be called
787
- result = mock_response.json()
788
- assert result == {"updated": True, "timestamp": "2023-12-01T12:00:00Z"}
789
-
790
- # Verify that aread was NOT called since we had Content-Length
791
- mock_response.aread.assert_not_called()
792
-
793
527
  @patch("port_ocean.helpers.retry.cast")
794
528
  def test_log_response_size_preserves_text_consumption(
795
529
  self, mock_cast: Mock
796
530
  ) -> None:
797
- """Test that _log_response_size preserves response for .text consumption."""
531
+ """When no Content-Length, no logging/reading; response.text still accessible."""
798
532
  mock_transport = Mock()
799
533
  mock_logger = Mock()
800
534
  mock_cast.return_value = mock_logger
@@ -804,128 +538,12 @@ class TestResponseSizeLoggingIntegration:
804
538
  mock_request.method = "GET"
805
539
  mock_request.url.host = "api.example.com"
806
540
 
807
- # Create a mock response with text content
808
- text_content = b"Hello, World! This is a test response."
809
541
  mock_response = Mock()
810
- mock_response.headers = {} # No Content-Length header to force content reading
811
- mock_response.read.return_value = text_content
542
+ mock_response.headers = {}
812
543
  mock_response.text = "Hello, World! This is a test response."
813
544
 
814
- # Call the logging function
815
545
  transport._log_response_size(mock_request, mock_response)
816
546
 
817
- # Verify logging occurred
818
- mock_logger.info.assert_called_once()
819
-
820
- # Verify that response.text can still be accessed
547
+ mock_logger.info.assert_not_called()
821
548
  assert mock_response.text == "Hello, World! This is a test response."
822
-
823
- # Verify that read was called and content was restored
824
- mock_response.read.assert_called_once()
825
- assert mock_response._content == text_content
826
-
827
- @pytest.mark.asyncio
828
- @patch("port_ocean.helpers.retry.cast")
829
- async def test_log_response_size_async_preserves_content_consumption(
830
- self, mock_cast: Mock
831
- ) -> None:
832
- """Test that _log_response_size_async preserves response for .content consumption."""
833
- mock_transport = Mock()
834
- mock_logger = Mock()
835
- mock_cast.return_value = mock_logger
836
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
837
-
838
- mock_request = Mock()
839
- mock_request.method = "GET"
840
- mock_request.url.host = "api.example.com"
841
-
842
- # Create a mock response with binary content
843
- binary_content = b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01"
844
- mock_response = Mock()
845
- mock_response.headers = {} # No Content-Length header to force content reading
846
- mock_response.aread = AsyncMock(return_value=binary_content)
847
- mock_response.content = binary_content
848
-
849
- # Call the async logging function
850
- await transport._log_response_size_async(mock_request, mock_response)
851
-
852
- # Verify logging occurred
853
- mock_logger.info.assert_called_once()
854
-
855
- # Verify that response.content can still be accessed
856
- assert mock_response.content == binary_content
857
-
858
- # Verify that aread was called and content was restored
859
- mock_response.aread.assert_called_once()
860
- assert mock_response._content == binary_content
861
-
862
- @patch("port_ocean.helpers.retry.cast")
863
- def test_log_response_size_error_handling_preserves_response(
864
- self, mock_cast: Mock
865
- ) -> None:
866
- """Test that _log_response_size error handling doesn't break response consumption."""
867
- mock_transport = Mock()
868
- mock_logger = Mock()
869
- mock_cast.return_value = mock_logger
870
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
871
-
872
- mock_request = Mock()
873
- mock_request.method = "GET"
874
- mock_request.url.host = "api.example.com"
875
-
876
- # Create a mock response that will fail on read
877
- mock_response = Mock()
878
- mock_response.headers = {} # No Content-Length header to force content reading
879
- mock_response.read.side_effect = Exception("Network error")
880
- mock_response.json.return_value = {"error": "handled gracefully"}
881
-
882
- # Call the logging function
883
- transport._log_response_size(mock_request, mock_response)
884
-
885
- # Verify error was logged
886
- mock_logger.error.assert_called_once_with(
887
- "Error getting response size: Network error"
888
- )
889
-
890
- # Verify that response.json() can still be called despite the error
891
- result = mock_response.json()
892
- assert result == {"error": "handled gracefully"}
893
-
894
- # Verify that read was attempted
895
- mock_response.read.assert_called_once()
896
-
897
- @pytest.mark.asyncio
898
- @patch("port_ocean.helpers.retry.cast")
899
- async def test_log_response_size_async_error_handling_preserves_response(
900
- self, mock_cast: Mock
901
- ) -> None:
902
- """Test that _log_response_size_async error handling doesn't break response consumption."""
903
- mock_transport = Mock()
904
- mock_logger = Mock()
905
- mock_cast.return_value = mock_logger
906
- transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
907
-
908
- mock_request = Mock()
909
- mock_request.method = "GET"
910
- mock_request.url.host = "api.example.com"
911
-
912
- # Create a mock response that will fail on aread
913
- mock_response = Mock()
914
- mock_response.headers = {} # No Content-Length header to force content reading
915
- mock_response.aread = AsyncMock(side_effect=Exception("Async network error"))
916
- mock_response.json.return_value = {"error": "handled gracefully"}
917
-
918
- # Call the async logging function
919
- await transport._log_response_size_async(mock_request, mock_response)
920
-
921
- # Verify error was logged
922
- mock_logger.error.assert_called_once_with(
923
- "Error getting response size: Async network error"
924
- )
925
-
926
- # Verify that response.json() can still be called despite the error
927
- result = mock_response.json()
928
- assert result == {"error": "handled gracefully"}
929
-
930
- # Verify that aread was attempted
931
- mock_response.aread.assert_called_once()
549
+ mock_response.read.assert_not_called()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.28.17
3
+ Version: 0.28.19
4
4
  Summary: Port Ocean is a CLI tool for managing your Port projects.
5
5
  Home-page: https://app.getport.io
6
6
  Keywords: ocean,port-ocean,port
@@ -125,7 +125,7 @@ port_ocean/core/integrations/mixins/handler.py,sha256=mZ7-0UlG3LcrwJttFbMe-R4xcO
125
125
  port_ocean/core/integrations/mixins/live_events.py,sha256=zM24dhNc7uHx9XYZ6toVhDADPA90EnpOmZxgDegFZbA,4196
126
126
  port_ocean/core/integrations/mixins/sync.py,sha256=Vm_898pLKBwfVewtwouDWsXoxcOLicnAy6pzyqqk6U8,4053
127
127
  port_ocean/core/integrations/mixins/sync_raw.py,sha256=TrdgwaCNbE-VEJBDRqWmLQR_1Epz6y5nEIbPaLZbe3A,41009
128
- port_ocean/core/integrations/mixins/utils.py,sha256=hRIkvxw1bIfilq6n_2fqUiv_5OSKFMl6HmJfimH2hTA,14590
128
+ port_ocean/core/integrations/mixins/utils.py,sha256=wdpQmapYEkKDqpnyyt_KLfu6Vrcbnk2pxrW8ikqNq8Q,14652
129
129
  port_ocean/core/models.py,sha256=DNbKpStMINI2lIekKprTqBevqkw_wFuFayN19w1aDfQ,2893
130
130
  port_ocean/core/ocean_types.py,sha256=bkLlTd8XfJK6_JDl0eXUHfE_NygqgiInSMwJ4YJH01Q,1399
131
131
  port_ocean/core/utils/entity_topological_sorter.py,sha256=MDUjM6OuDy4Xj68o-7InNN0w1jqjxeDfeY8U02vySNI,3081
@@ -144,11 +144,11 @@ port_ocean/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
144
144
  port_ocean/helpers/async_client.py,sha256=M8gKUjX8ZwRbmJ-U6KNq-p-nfGr0CwHdS0eN_pbZAJ0,2103
145
145
  port_ocean/helpers/metric/metric.py,sha256=6SMxov1WcZAV0NehMGMqWiLoOIpw-2fOpVbtPWhmW1c,14544
146
146
  port_ocean/helpers/metric/utils.py,sha256=1lAgrxnZLuR_wUNDyPOPzLrm32b8cDdioob2lvnPQ1A,1619
147
- port_ocean/helpers/retry.py,sha256=fkKL_dSNKbGLpa9qi3Ceu2yCqcnzC0OV3dcEWo_kPHA,22067
147
+ port_ocean/helpers/retry.py,sha256=yL0TJvA-0jol-zyUO57pYBCRmq3ZglkrgCdX3QZ6tHs,20288
148
148
  port_ocean/helpers/stream.py,sha256=_UwsThzXynxWzL8OlBT1pmb2evZBi9HaaqeAGNuTuOI,2338
149
149
  port_ocean/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
150
  port_ocean/log/handlers.py,sha256=LJ1WAfq7wYCrBpeLPihMKmWjdSahKKXNHFMRYkbk0Co,3630
151
- port_ocean/log/logger_setup.py,sha256=5JxGlg7TKDbYD2ladgaHufCv6PTJXvdQJ8l6cP3MKFA,2700
151
+ port_ocean/log/logger_setup.py,sha256=wcr5WOkYRtng4pW6ZRl4Av3GqtZ2omSWIqYhB_8Duuc,2700
152
152
  port_ocean/log/sensetive.py,sha256=lVKiZH6b7TkrZAMmhEJRhcl67HNM94e56x12DwFgCQk,2920
153
153
  port_ocean/middlewares.py,sha256=9wYCdyzRZGK1vjEJ28FY_DkfwDNENmXp504UKPf5NaQ,2727
154
154
  port_ocean/ocean.py,sha256=1aurpHc47BecmnaVDVmR8LCqm5Nfa3-ltkM_xZPxu1w,9570
@@ -193,7 +193,7 @@ port_ocean/tests/helpers/integration.py,sha256=_RxS-RHpu11lrbhUXYPZp862HLWx8AoD7
193
193
  port_ocean/tests/helpers/ocean_app.py,sha256=N06vcNI1klqdcNFq-PXL5vm77u-hODsOSXnj9p8d1AI,2249
194
194
  port_ocean/tests/helpers/port_client.py,sha256=S0CXvZWUoHFWWQUOEgdkDammK9Fs3R06wx0flaMrTsg,647
195
195
  port_ocean/tests/helpers/smoke_test.py,sha256=_9aJJFRfuGJEg2D2YQJVJRmpreS6gEPHHQq8Q01x4aQ,2697
196
- port_ocean/tests/helpers/test_retry.py,sha256=4wuacabVZTGOICCd0dHlVklhLytsCGu2zjo8hnqEeEs,35912
196
+ port_ocean/tests/helpers/test_retry.py,sha256=w1p0flGunT0NxrUVtlR5FvSDg_vXGrlWyg_e6tJRVn4,20435
197
197
  port_ocean/tests/log/test_handlers.py,sha256=x2P2Hd6Cb3sQafIE3TRGltbbHeiFHaiEjwRn9py_03g,2165
198
198
  port_ocean/tests/test_metric.py,sha256=gDdeJcqJDQ_o3VrYrW23iZyw2NuUsyATdrygSXhcDuQ,8096
199
199
  port_ocean/tests/test_ocean.py,sha256=bsXKGTVEjwLSbR7-qSmI4GZ-EzDo0eBE3TNSMsWzYxM,1502
@@ -211,8 +211,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
211
211
  port_ocean/utils/signal.py,sha256=J1sI-e_32VHP_VUa5bskLMFoJjJOAk5isrnewKDikUI,2125
212
212
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
213
213
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
214
- port_ocean-0.28.17.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
215
- port_ocean-0.28.17.dist-info/METADATA,sha256=rHk9ILkvieFzWeeX1dljjZ0wfjN9EPX9NDl5tLwOFDc,7016
216
- port_ocean-0.28.17.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
217
- port_ocean-0.28.17.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
218
- port_ocean-0.28.17.dist-info/RECORD,,
214
+ port_ocean-0.28.19.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
215
+ port_ocean-0.28.19.dist-info/METADATA,sha256=l_VsAxOD03U_rAV9Q-WE8IplcwAiTXZYhKR0TDP3_AI,7016
216
+ port_ocean-0.28.19.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
217
+ port_ocean-0.28.19.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
218
+ port_ocean-0.28.19.dist-info/RECORD,,