port-ocean 0.27.9__tar.gz → 0.28.0__tar.gz

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.
Files changed (214) hide show
  1. {port_ocean-0.27.9 → port_ocean-0.28.0}/PKG-INFO +1 -1
  2. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/authentication.py +2 -0
  3. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/client.py +5 -2
  4. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/mixins/integrations.py +1 -1
  5. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/config/settings.py +1 -1
  6. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/helpers/async_client.py +7 -8
  7. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/helpers/retry.py +162 -72
  8. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/ocean.py +11 -12
  9. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/conftest.py +7 -1
  10. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/mixins/test_live_events.py +23 -13
  11. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +32 -27
  12. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/helpers/port_client.py +1 -0
  13. port_ocean-0.28.0/port_ocean/tests/helpers/test_retry.py +309 -0
  14. {port_ocean-0.27.9 → port_ocean-0.28.0}/pyproject.toml +1 -1
  15. {port_ocean-0.27.9 → port_ocean-0.28.0}/LICENSE.md +0 -0
  16. {port_ocean-0.27.9 → port_ocean-0.28.0}/README.md +0 -0
  17. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/Dockerfile.Deb +0 -0
  18. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/Dockerfile.alpine +0 -0
  19. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/Dockerfile.base.builder +0 -0
  20. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/Dockerfile.base.runner +0 -0
  21. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/Dockerfile.dockerignore +0 -0
  22. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/Dockerfile.local +0 -0
  23. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/Makefile +0 -0
  24. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/README.md +0 -0
  25. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/entry_local.sh +0 -0
  26. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/grpcio.sh +0 -0
  27. {port_ocean-0.27.9 → port_ocean-0.28.0}/integrations/_infra/init.sh +0 -0
  28. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/__init__.py +0 -0
  29. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/bootstrap.py +0 -0
  30. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cache/__init__.py +0 -0
  31. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cache/base.py +0 -0
  32. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cache/disk.py +0 -0
  33. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cache/errors.py +0 -0
  34. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cache/memory.py +0 -0
  35. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/__init__.py +0 -0
  36. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cli.py +0 -0
  37. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/__init__.py +0 -0
  38. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  39. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/defaults/clean.py +0 -0
  40. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/defaults/dock.py +0 -0
  41. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/defaults/group.py +0 -0
  42. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/list_integrations.py +0 -0
  43. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/main.py +0 -0
  44. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/new.py +0 -0
  45. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/pull.py +0 -0
  46. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/sail.py +0 -0
  47. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/commands/version.py +0 -0
  48. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  49. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  50. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  51. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  52. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  53. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  54. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  55. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  56. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  57. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  58. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  59. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  60. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  61. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  62. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  63. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  64. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  65. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  66. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  67. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  68. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  69. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/cli/utils.py +0 -0
  70. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/__init__.py +0 -0
  71. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/auth/__init__.py +0 -0
  72. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/auth/auth_client.py +0 -0
  73. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/auth/oauth_client.py +0 -0
  74. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/__init__.py +0 -0
  75. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/mixins/__init__.py +0 -0
  76. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  77. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/mixins/entities.py +0 -0
  78. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/mixins/migrations.py +0 -0
  79. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/mixins/organization.py +0 -0
  80. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/retry_transport.py +0 -0
  81. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/types.py +0 -0
  82. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/clients/port/utils.py +0 -0
  83. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/config/__init__.py +0 -0
  84. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/config/base.py +0 -0
  85. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/config/dynamic.py +0 -0
  86. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/consumers/__init__.py +0 -0
  87. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/consumers/kafka_consumer.py +0 -0
  88. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/context/__init__.py +0 -0
  89. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/context/event.py +0 -0
  90. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/context/metric_resource.py +0 -0
  91. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/context/ocean.py +0 -0
  92. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/context/resource.py +0 -0
  93. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/__init__.py +0 -0
  94. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/defaults/__init__.py +0 -0
  95. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/defaults/clean.py +0 -0
  96. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/defaults/common.py +0 -0
  97. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/defaults/initialize.py +0 -0
  98. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/__init__.py +0 -0
  99. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/base.py +0 -0
  100. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/factory.py +0 -0
  101. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/http.py +0 -0
  102. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/kafka.py +0 -0
  103. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/once.py +0 -0
  104. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/polling.py +0 -0
  105. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/event_listener/webhooks_only.py +0 -0
  106. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/__init__.py +0 -0
  107. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/base.py +0 -0
  108. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  109. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  110. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  111. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  112. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  113. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  114. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  115. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  116. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  117. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  118. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  119. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  120. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  121. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/queue/__init__.py +0 -0
  122. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/queue/abstract_queue.py +0 -0
  123. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/queue/group_queue.py +0 -0
  124. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/queue/local_queue.py +0 -0
  125. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  126. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
  127. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/webhook/__init__.py +0 -0
  128. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +0 -0
  129. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/webhook/processor_manager.py +0 -0
  130. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/handlers/webhook/webhook_event.py +0 -0
  131. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/__init__.py +0 -0
  132. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/base.py +0 -0
  133. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  134. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/mixins/events.py +0 -0
  135. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/mixins/handler.py +0 -0
  136. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/mixins/live_events.py +0 -0
  137. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/mixins/sync.py +0 -0
  138. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/mixins/sync_raw.py +0 -0
  139. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/integrations/mixins/utils.py +0 -0
  140. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/models.py +0 -0
  141. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/ocean_types.py +0 -0
  142. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
  143. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/core/utils/utils.py +0 -0
  144. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/debug_cli.py +0 -0
  145. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/__init__.py +0 -0
  146. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/api.py +0 -0
  147. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/base.py +0 -0
  148. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/clients.py +0 -0
  149. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/context.py +0 -0
  150. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/core.py +0 -0
  151. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/port_defaults.py +0 -0
  152. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/utils.py +0 -0
  153. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/exceptions/webhook_processor.py +0 -0
  154. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/helpers/__init__.py +0 -0
  155. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/helpers/metric/metric.py +0 -0
  156. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/helpers/metric/utils.py +0 -0
  157. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/helpers/stream.py +0 -0
  158. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/log/__init__.py +0 -0
  159. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/log/handlers.py +0 -0
  160. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/log/logger_setup.py +0 -0
  161. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/log/sensetive.py +0 -0
  162. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/middlewares.py +0 -0
  163. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/py.typed +0 -0
  164. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/run.py +0 -0
  165. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/sonar-project.properties +0 -0
  166. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/__init__.py +0 -0
  167. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/cache/__init__.py +0 -0
  168. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/cache/test_disk_cache.py +0 -0
  169. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/cache/test_memory_cache.py +0 -0
  170. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/clients/__init__.py +0 -0
  171. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/clients/oauth/__init__.py +0 -0
  172. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/clients/oauth/test_oauth_client.py +0 -0
  173. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
  174. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/clients/port/mixins/test_integrations.py +0 -0
  175. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
  176. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/config/test_config.py +0 -0
  177. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/conftest.py +0 -0
  178. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/defaults/test_common.py +0 -0
  179. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/event_listener/test_kafka.py +0 -0
  180. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -0
  181. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  182. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +0 -0
  183. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
  184. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/port_app_config/test_base.py +0 -0
  185. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/queue/test_group_queue.py +0 -0
  186. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
  187. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
  188. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
  189. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/test_utils.py +0 -0
  190. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
  191. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
  192. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/helpers/__init__.py +0 -0
  193. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/helpers/fake_port_api.py +0 -0
  194. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/helpers/fixtures.py +0 -0
  195. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/helpers/integration.py +0 -0
  196. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/helpers/ocean_app.py +0 -0
  197. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/helpers/smoke_test.py +0 -0
  198. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/log/test_handlers.py +0 -0
  199. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/test_metric.py +0 -0
  200. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/test_ocean.py +0 -0
  201. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/test_smoke.py +0 -0
  202. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/utils/test_async_iterators.py +0 -0
  203. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/tests/utils/test_cache.py +0 -0
  204. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/__init__.py +0 -0
  205. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/async_http.py +0 -0
  206. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/async_iterators.py +0 -0
  207. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/cache.py +0 -0
  208. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/ipc.py +0 -0
  209. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/misc.py +0 -0
  210. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/queue_utils.py +0 -0
  211. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/repeat.py +0 -0
  212. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/signal.py +0 -0
  213. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/utils/time.py +0 -0
  214. {port_ocean-0.27.9 → port_ocean-0.28.0}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.27.9
3
+ Version: 0.28.0
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
@@ -35,6 +35,7 @@ class PortAuthentication:
35
35
  integration_identifier: str,
36
36
  integration_type: str,
37
37
  integration_version: str,
38
+ ingest_url: str,
38
39
  ):
39
40
  self.client = client
40
41
  self.api_url = api_url
@@ -43,6 +44,7 @@ class PortAuthentication:
43
44
  self.integration_identifier = integration_identifier
44
45
  self.integration_type = integration_type
45
46
  self.integration_version = integration_version
47
+ self.ingest_url = ingest_url
46
48
  self.last_token_object: TokenResponse | None = None
47
49
 
48
50
  async def _get_token(self, client_id: str, client_secret: str) -> TokenResponse:
@@ -1,3 +1,5 @@
1
+ from typing import Any
2
+
1
3
  from loguru import logger
2
4
 
3
5
  from port_ocean.clients.port.authentication import PortAuthentication
@@ -10,11 +12,10 @@ from port_ocean.clients.port.types import (
10
12
  KafkaCreds,
11
13
  )
12
14
  from port_ocean.clients.port.utils import (
13
- handle_port_status_code,
14
15
  get_internal_http_client,
16
+ handle_port_status_code,
15
17
  )
16
18
  from port_ocean.exceptions.clients import KafkaCredentialsNotFound
17
- from typing import Any
18
19
 
19
20
 
20
21
  class PortClient(
@@ -32,6 +33,7 @@ class PortClient(
32
33
  integration_identifier: str,
33
34
  integration_type: str,
34
35
  integration_version: str,
36
+ ingest_url: str,
35
37
  ):
36
38
  self.api_url = f"{base_url}/v1"
37
39
  self.client = get_internal_http_client(self)
@@ -43,6 +45,7 @@ class PortClient(
43
45
  integration_identifier,
44
46
  integration_type,
45
47
  integration_version,
48
+ ingest_url,
46
49
  )
47
50
  EntityClientMixin.__init__(self, self.auth, self.client)
48
51
  IntegrationClientMixin.__init__(
@@ -296,7 +296,7 @@ class IntegrationClientMixin:
296
296
  logger.debug("starting POST raw data request", raw_data=raw_data)
297
297
  headers = await self.auth.headers()
298
298
  response = await self.client.post(
299
- f"{self.auth.api_url}/lakehouse/integration/{self.integration_identifier}/sync/{sync_id}/kind/{kind}/items",
299
+ f"{self.auth.ingest_url}/lakehouse/integration-type/{self.auth.integration_type}/integration/{self.integration_identifier}/sync/{sync_id}/kind/{kind}/items",
300
300
  headers=headers,
301
301
  json={
302
302
  "items": raw_data,
@@ -9,7 +9,6 @@ from pydantic.main import BaseModel
9
9
 
10
10
  from port_ocean.config.base import BaseOceanModel, BaseOceanSettings
11
11
  from port_ocean.core.event_listener import EventListenerSettingsType
12
-
13
12
  from port_ocean.core.models import (
14
13
  CachingStorageMode,
15
14
  CreatePortResourcesOrigin,
@@ -47,6 +46,7 @@ class PortSettings(BaseOceanModel, extra=Extra.allow):
47
46
  client_secret: str = Field(..., sensitive=True)
48
47
  base_url: AnyHttpUrl = parse_obj_as(AnyHttpUrl, "https://api.getport.io")
49
48
  port_app_config_cache_ttl: int = 60
49
+ ingest_url: AnyHttpUrl = parse_obj_as(AnyHttpUrl, "https://ingest.getport.io")
50
50
 
51
51
 
52
52
  class IntegrationSettings(BaseOceanModel, extra=Extra.allow):
@@ -3,7 +3,7 @@ from typing import Any, Type
3
3
  import httpx
4
4
  from loguru import logger
5
5
 
6
- from port_ocean.helpers.retry import RetryTransport
6
+ from port_ocean.helpers.retry import RetryTransport, RetryConfig
7
7
  from port_ocean.helpers.stream import Stream
8
8
 
9
9
 
@@ -18,10 +18,12 @@ class OceanAsyncClient(httpx.AsyncClient):
18
18
  self,
19
19
  transport_class: Type[RetryTransport] = RetryTransport,
20
20
  transport_kwargs: dict[str, Any] | None = None,
21
+ retry_config: RetryConfig | None = None,
21
22
  **kwargs: Any,
22
23
  ):
23
24
  self._transport_kwargs = transport_kwargs
24
25
  self._transport_class = transport_class
26
+ self._retry_config = retry_config
25
27
  super().__init__(**kwargs)
26
28
 
27
29
  def _init_transport( # type: ignore[override]
@@ -33,9 +35,8 @@ class OceanAsyncClient(httpx.AsyncClient):
33
35
  return super()._init_transport(transport=transport, **kwargs)
34
36
 
35
37
  return self._transport_class(
36
- wrapped_transport=httpx.AsyncHTTPTransport(
37
- **kwargs,
38
- ),
38
+ wrapped_transport=httpx.AsyncHTTPTransport(**kwargs),
39
+ retry_config=self._retry_config,
39
40
  logger=logger,
40
41
  **(self._transport_kwargs or {}),
41
42
  )
@@ -44,10 +45,8 @@ class OceanAsyncClient(httpx.AsyncClient):
44
45
  self, proxy: httpx.Proxy, **kwargs: Any
45
46
  ) -> httpx.AsyncBaseTransport:
46
47
  return self._transport_class(
47
- wrapped_transport=httpx.AsyncHTTPTransport(
48
- proxy=proxy,
49
- **kwargs,
50
- ),
48
+ wrapped_transport=httpx.AsyncHTTPTransport(proxy=proxy, **kwargs),
49
+ retry_config=self._retry_config,
51
50
  logger=logger,
52
51
  **(self._transport_kwargs or {}),
53
52
  )
@@ -4,12 +4,24 @@ import time
4
4
  from datetime import datetime
5
5
  from functools import partial
6
6
  from http import HTTPStatus
7
- from typing import Any, Callable, Coroutine, Iterable, Mapping, Union, cast
7
+ from typing import (
8
+ Any,
9
+ Callable,
10
+ Coroutine,
11
+ Iterable,
12
+ Mapping,
13
+ Union,
14
+ cast,
15
+ Optional,
16
+ List,
17
+ )
8
18
  import httpx
9
19
  from dateutil.parser import isoparse
10
20
  import logging
11
21
 
22
+ MAX_BACKOFF_WAIT_IN_SECONDS = 60
12
23
  _ON_RETRY_CALLBACK: Callable[[httpx.Request], httpx.Request] | None = None
24
+ _RETRY_CONFIG_CALLBACK: Callable[[], "RetryConfig"] | None = None
13
25
 
14
26
 
15
27
  def register_on_retry_callback(
@@ -19,6 +31,92 @@ def register_on_retry_callback(
19
31
  _ON_RETRY_CALLBACK = _on_retry_callback
20
32
 
21
33
 
34
+ def register_retry_config_callback(
35
+ retry_config_callback: Callable[[], "RetryConfig"]
36
+ ) -> None:
37
+ """Register a callback function that returns a RetryConfig instance.
38
+
39
+ The callback will be called when a RetryTransport needs to be created.
40
+
41
+ Args:
42
+ retry_config_callback: A function that returns a RetryConfig instance
43
+ """
44
+ global _RETRY_CONFIG_CALLBACK
45
+ _RETRY_CONFIG_CALLBACK = retry_config_callback
46
+
47
+
48
+ class RetryConfig:
49
+ """Configuration class for retry behavior that can be customized per integration."""
50
+
51
+ def __init__(
52
+ self,
53
+ max_attempts: int = 10,
54
+ max_backoff_wait: float = MAX_BACKOFF_WAIT_IN_SECONDS,
55
+ base_delay: float = 0.1,
56
+ jitter_ratio: float = 0.1,
57
+ respect_retry_after_header: bool = True,
58
+ retryable_methods: Optional[Iterable[str]] = None,
59
+ retry_status_codes: Optional[Iterable[int]] = None,
60
+ retry_after_headers: Optional[List[str]] = None,
61
+ additional_retry_status_codes: Optional[Iterable[int]] = None,
62
+ ):
63
+ """
64
+ Initialize retry configuration.
65
+
66
+ Args:
67
+ max_attempts: Maximum number of retry attempts
68
+ max_backoff_wait: Maximum backoff wait time in seconds
69
+ base_delay: Base delay for exponential backoff
70
+ jitter_ratio: Jitter ratio for backoff (0-0.5)
71
+ respect_retry_after_header: Whether to respect Retry-After header
72
+ retryable_methods: HTTP methods that can be retried (overrides defaults if provided)
73
+ retry_status_codes: DEPRECATED - use additional_retry_status_codes instead
74
+ retry_after_headers: Custom headers to check for retry timing (e.g., ['X-RateLimit-Reset', 'Retry-After'])
75
+ additional_retry_status_codes: Additional status codes to retry (extends system defaults)
76
+ """
77
+ self.max_attempts = max_attempts
78
+ self.max_backoff_wait = max_backoff_wait
79
+ self.base_delay = base_delay
80
+ self.jitter_ratio = jitter_ratio
81
+ self.respect_retry_after_header = respect_retry_after_header
82
+
83
+ # Default retryable methods - always include these unless explicitly overridden
84
+ default_methods = frozenset(
85
+ ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"]
86
+ )
87
+ self.retryable_methods = (
88
+ frozenset(retryable_methods) if retryable_methods else default_methods
89
+ )
90
+
91
+ # Default retry status codes - always include these for system reliability
92
+ default_status_codes = frozenset(
93
+ [
94
+ HTTPStatus.TOO_MANY_REQUESTS,
95
+ HTTPStatus.BAD_GATEWAY,
96
+ HTTPStatus.SERVICE_UNAVAILABLE,
97
+ HTTPStatus.GATEWAY_TIMEOUT,
98
+ HTTPStatus.UNAUTHORIZED,
99
+ HTTPStatus.BAD_REQUEST,
100
+ ]
101
+ )
102
+
103
+ # Additional status codes to retry (extends defaults)
104
+ additional_codes = (
105
+ frozenset(additional_retry_status_codes)
106
+ if additional_retry_status_codes
107
+ else frozenset()
108
+ )
109
+
110
+ # Combine defaults with additional codes for extensibility
111
+ self.retry_status_codes = default_status_codes | additional_codes
112
+ self.retry_after_headers = retry_after_headers or ["Retry-After"]
113
+
114
+ if jitter_ratio < 0 or jitter_ratio > 0.5:
115
+ raise ValueError(
116
+ f"Jitter ratio should be between 0 and 0.5, actual {jitter_ratio}"
117
+ )
118
+
119
+
22
120
  # Adapted from https://github.com/encode/httpx/issues/108#issuecomment-1434439481
23
121
  class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
24
122
  """
@@ -41,32 +139,16 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
41
139
  ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"].
42
140
  retry_status_codes (Iterable[int], optional): The HTTP status codes that can be retried. Defaults to
43
141
  [429, 502, 503, 504].
142
+ retry_config (RetryConfig, optional): Configuration for retry behavior. If not provided, uses defaults.
143
+ logger (Any, optional): The logger to use for logging retries.
44
144
 
45
145
  Attributes:
46
146
  _wrapped_transport (Union[httpx.BaseTransport, httpx.AsyncBaseTransport]): The underlying HTTP transport
47
147
  being wrapped.
48
- _max_attempts (int): The maximum number of times to retry a request.
49
- _backoff_factor (float): The factor by which the wait time increases with each retry attempt.
50
- _respect_retry_after_header (bool): Whether to respect the Retry-After header in HTTP responses.
51
- _retryable_methods (frozenset): The HTTP methods that can be retried.
52
- _retry_status_codes (frozenset): The HTTP status codes that can be retried.
53
- _jitter_ratio (float): The amount of jitter to add to the backoff time.
54
- _max_backoff_wait (float): The maximum time to wait between retries in seconds.
148
+ _retry_config (RetryConfig): The retry configuration object.
149
+ _logger (Any): The logger to use for logging retries.
55
150
  """
56
151
 
57
- RETRYABLE_METHODS = frozenset(["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"])
58
- RETRYABLE_STATUS_CODES = frozenset(
59
- [
60
- HTTPStatus.TOO_MANY_REQUESTS,
61
- HTTPStatus.BAD_GATEWAY,
62
- HTTPStatus.SERVICE_UNAVAILABLE,
63
- HTTPStatus.GATEWAY_TIMEOUT,
64
- HTTPStatus.UNAUTHORIZED,
65
- HTTPStatus.BAD_REQUEST,
66
- ]
67
- )
68
- MAX_BACKOFF_WAIT_IN_SECONDS = 60
69
-
70
152
  def __init__(
71
153
  self,
72
154
  wrapped_transport: Union[httpx.BaseTransport, httpx.AsyncBaseTransport],
@@ -77,6 +159,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
77
159
  respect_retry_after_header: bool = True,
78
160
  retryable_methods: Iterable[str] | None = None,
79
161
  retry_status_codes: Iterable[int] | None = None,
162
+ retry_config: Optional[RetryConfig] = None,
80
163
  logger: Any | None = None,
81
164
  ) -> None:
82
165
  """
@@ -106,29 +189,27 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
106
189
  retry_status_codes (Iterable[int], optional):
107
190
  The HTTP status codes that can be retried.
108
191
  Defaults to [429, 502, 503, 504].
192
+ retry_config (RetryConfig, optional):
193
+ Configuration for retry behavior. If not provided, uses default configuration.
109
194
  logger (Any): The logger to use for logging retries.
110
195
  """
111
196
  self._wrapped_transport = wrapped_transport
112
- if jitter_ratio < 0 or jitter_ratio > 0.5:
113
- raise ValueError(
114
- f"Jitter ratio should be between 0 and 0.5, actual {jitter_ratio}"
197
+
198
+ if retry_config is not None:
199
+ self._retry_config = retry_config
200
+ elif _RETRY_CONFIG_CALLBACK is not None:
201
+ self._retry_config = _RETRY_CONFIG_CALLBACK()
202
+ else:
203
+ self._retry_config = RetryConfig(
204
+ max_attempts=max_attempts,
205
+ max_backoff_wait=max_backoff_wait,
206
+ base_delay=base_delay,
207
+ jitter_ratio=jitter_ratio,
208
+ respect_retry_after_header=respect_retry_after_header,
209
+ retryable_methods=retryable_methods,
210
+ retry_status_codes=retry_status_codes,
115
211
  )
116
212
 
117
- self._max_attempts = max_attempts
118
- self._base_delay = base_delay
119
- self._respect_retry_after_header = respect_retry_after_header
120
- self._retryable_methods = (
121
- frozenset(retryable_methods)
122
- if retryable_methods
123
- else self.RETRYABLE_METHODS
124
- )
125
- self._retry_status_codes = (
126
- frozenset(retry_status_codes)
127
- if retry_status_codes
128
- else self.RETRYABLE_STATUS_CODES
129
- )
130
- self._jitter_ratio = jitter_ratio
131
- self._max_backoff_wait = max_backoff_wait
132
213
  self._logger = logger
133
214
 
134
215
  def handle_request(self, request: httpx.Request) -> httpx.Response:
@@ -206,12 +287,13 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
206
287
  transport.close()
207
288
 
208
289
  def _is_retryable_method(self, request: httpx.Request) -> bool:
209
- return request.method in self._retryable_methods or request.extensions.get(
210
- "retryable", False
290
+ return (
291
+ request.method in self._retry_config.retryable_methods
292
+ or request.extensions.get("retryable", False)
211
293
  )
212
294
 
213
295
  def _should_retry(self, response: httpx.Response) -> bool:
214
- return response.status_code in self._retry_status_codes
296
+ return response.status_code in self._retry_config.retry_status_codes
215
297
 
216
298
  def _log_error(
217
299
  self,
@@ -314,46 +396,54 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
314
396
  )
315
397
 
316
398
  async def _should_retry_async(self, response: httpx.Response) -> bool:
317
- return response.status_code in self._retry_status_codes
399
+ return response.status_code in self._retry_config.retry_status_codes
318
400
 
319
401
  def _calculate_sleep(
320
402
  self, attempts_made: int, headers: Union[httpx.Headers, Mapping[str, str]]
321
403
  ) -> float:
322
- # Retry-After
323
- # The Retry-After response HTTP header indicates how long the user agent should wait before
324
- # making a follow-up request. There are three main cases this header is used:
325
- # - When sent with a 503 (Service Unavailable) response, this indicates how long the service
326
- # is expected to be unavailable.
327
- # - When sent with a 429 (Too Many Requests) response, this indicates how long to wait before
328
- # making a new request.
329
- # - When sent with a redirect response, such as 301 (Moved Permanently), this indicates the
330
- # minimum time that the user agent is asked to wait before issuing the redirected request.
331
- retry_after_header = (headers.get("Retry-After") or "").strip()
332
- if self._respect_retry_after_header and retry_after_header:
333
- if retry_after_header.isdigit():
334
- return float(retry_after_header)
335
-
336
- try:
337
- parsed_date = isoparse(
338
- retry_after_header
339
- ).astimezone() # converts to local time
340
- diff = (parsed_date - datetime.now().astimezone()).total_seconds()
341
- if diff > 0:
342
- return min(diff, self._max_backoff_wait)
343
- except ValueError:
344
- pass
345
-
346
- backoff = self._base_delay * (2 ** (attempts_made - 1))
347
- jitter = (backoff * self._jitter_ratio) * random.choice([1, -1])
404
+ # Check custom retry headers first, then fall back to Retry-After
405
+ if self._retry_config.respect_retry_after_header:
406
+ for header_name in self._retry_config.retry_after_headers:
407
+ if header_value := (headers.get(header_name) or "").strip():
408
+ sleep_time = self._parse_retry_header(header_value)
409
+ if sleep_time is not None:
410
+ return min(sleep_time, self._retry_config.max_backoff_wait)
411
+
412
+ # Fall back to exponential backoff
413
+ backoff = self._retry_config.base_delay * (2 ** (attempts_made - 1))
414
+ jitter = (backoff * self._retry_config.jitter_ratio) * random.choice([1, -1])
348
415
  total_backoff = backoff + jitter
349
- return min(total_backoff, self._max_backoff_wait)
416
+ return min(total_backoff, self._retry_config.max_backoff_wait)
417
+
418
+ def _parse_retry_header(self, header_value: str) -> Optional[float]:
419
+ """Parse retry header value and return sleep time in seconds.
420
+
421
+ Args:
422
+ header_value: The header value to parse (e.g., "30", "2023-12-01T12:00:00Z")
423
+
424
+ Returns:
425
+ Sleep time in seconds if parsing succeeds, None if the header value cannot be parsed
426
+ """
427
+ if header_value.isdigit():
428
+ return float(header_value)
429
+
430
+ try:
431
+ # Try to parse as ISO date (common for rate limit headers like X-RateLimit-Reset)
432
+ parsed_date = isoparse(header_value).astimezone()
433
+ diff = (parsed_date - datetime.now().astimezone()).total_seconds()
434
+ if diff > 0:
435
+ return diff
436
+ except ValueError:
437
+ pass
438
+
439
+ return None
350
440
 
351
441
  async def _retry_operation_async(
352
442
  self,
353
443
  request: httpx.Request,
354
444
  send_method: Callable[..., Coroutine[Any, Any, httpx.Response]],
355
445
  ) -> httpx.Response:
356
- remaining_attempts = self._max_attempts
446
+ remaining_attempts = self._retry_config.max_attempts
357
447
  attempts_made = 0
358
448
  response: httpx.Response | None = None
359
449
  error: Exception | None = None
@@ -403,7 +493,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
403
493
  request: httpx.Request,
404
494
  send_method: Callable[..., httpx.Response],
405
495
  ) -> httpx.Response:
406
- remaining_attempts = self._max_attempts
496
+ remaining_attempts = self._retry_config.max_attempts
407
497
  attempts_made = 0
408
498
  response: httpx.Response | None = None
409
499
  error: Exception | None = None
@@ -1,21 +1,18 @@
1
1
  import asyncio
2
2
  import sys
3
- from contextlib import asynccontextmanager
4
3
  import threading
4
+ from contextlib import asynccontextmanager
5
5
  from typing import Any, AsyncIterator, Callable, Dict, Type
6
6
 
7
- from port_ocean.cache.base import CacheProvider
8
- from port_ocean.cache.disk import DiskCacheProvider
9
- from port_ocean.cache.memory import InMemoryCacheProvider
10
- from port_ocean.core.models import ProcessExecutionMode
11
- import port_ocean.helpers.metric.metric
12
-
13
- from fastapi import FastAPI, APIRouter
14
-
7
+ from fastapi import APIRouter, FastAPI
15
8
  from loguru import logger
16
9
  from pydantic import BaseModel
17
10
  from starlette.types import Receive, Scope, Send
18
11
 
12
+ import port_ocean.helpers.metric.metric
13
+ from port_ocean.cache.base import CacheProvider
14
+ from port_ocean.cache.disk import DiskCacheProvider
15
+ from port_ocean.cache.memory import InMemoryCacheProvider
19
16
  from port_ocean.clients.port.client import PortClient
20
17
  from port_ocean.config.settings import (
21
18
  IntegrationConfiguration,
@@ -26,16 +23,17 @@ from port_ocean.context.ocean import (
26
23
  ocean,
27
24
  )
28
25
  from port_ocean.core.handlers.resync_state_updater import ResyncStateUpdater
26
+ from port_ocean.core.handlers.webhook.processor_manager import (
27
+ LiveEventsProcessorManager,
28
+ )
29
29
  from port_ocean.core.integrations.base import BaseIntegration
30
+ from port_ocean.core.models import ProcessExecutionMode
30
31
  from port_ocean.log.sensetive import sensitive_log_filter
31
32
  from port_ocean.middlewares import request_handler
32
33
  from port_ocean.utils.misc import IntegrationStateStatus
33
34
  from port_ocean.utils.repeat import repeat_every
34
35
  from port_ocean.utils.signal import signal_handler
35
36
  from port_ocean.version import __integration_version__
36
- from port_ocean.core.handlers.webhook.processor_manager import (
37
- LiveEventsProcessorManager,
38
- )
39
37
 
40
38
 
41
39
  class Ocean:
@@ -69,6 +67,7 @@ class Ocean:
69
67
  integration_identifier=self.config.integration.identifier,
70
68
  integration_type=self.config.integration.type,
71
69
  integration_version=__integration_version__,
70
+ ingest_url=self.config.port.ingest_url,
72
71
  )
73
72
  self.cache_provider: CacheProvider = self._get_caching_provider()
74
73
  self.process_execution_mode: ProcessExecutionMode = (
@@ -96,7 +96,13 @@ def mock_http_client() -> MagicMock:
96
96
  @pytest.fixture
97
97
  def mock_port_client(mock_http_client: MagicMock) -> PortClient:
98
98
  mock_port_client = PortClient(
99
- MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock()
99
+ MagicMock(),
100
+ MagicMock(),
101
+ MagicMock(),
102
+ MagicMock(),
103
+ MagicMock(),
104
+ MagicMock(),
105
+ MagicMock(),
100
106
  )
101
107
  mock_port_client.auth = AsyncMock()
102
108
  mock_port_client.auth.headers = AsyncMock(
@@ -1,7 +1,9 @@
1
1
  from typing import Any
2
- from httpx import Response
3
- import pytest
4
2
  from unittest.mock import AsyncMock, MagicMock, patch
3
+
4
+ import pytest
5
+ from httpx import Response
6
+
5
7
  from port_ocean.clients.port.client import PortClient
6
8
  from port_ocean.clients.port.types import UserAgentType
7
9
  from port_ocean.context.ocean import PortOceanContext
@@ -11,8 +13,6 @@ from port_ocean.core.handlers.entities_state_applier.port.applier import (
11
13
  from port_ocean.core.handlers.entity_processor.jq_entity_processor import (
12
14
  JQEntityProcessor,
13
15
  )
14
- from port_ocean.core.handlers.webhook.webhook_event import WebhookEventRawResults
15
- from port_ocean.core.integrations.mixins.live_events import LiveEventsMixin
16
16
  from port_ocean.core.handlers.port_app_config.models import (
17
17
  EntityMapping,
18
18
  MappingsConfig,
@@ -21,6 +21,8 @@ from port_ocean.core.handlers.port_app_config.models import (
21
21
  ResourceConfig,
22
22
  Selector,
23
23
  )
24
+ from port_ocean.core.handlers.webhook.webhook_event import WebhookEventRawResults
25
+ from port_ocean.core.integrations.mixins.live_events import LiveEventsMixin
24
26
  from port_ocean.core.models import Entity
25
27
  from port_ocean.core.ocean_types import CalculationResult, EntitySelectorDiff
26
28
  from port_ocean.ocean import Ocean
@@ -253,7 +255,13 @@ def mock_port_app_config_handler(
253
255
  @pytest.fixture
254
256
  def mock_port_client(mock_http_client: MagicMock) -> PortClient:
255
257
  mock_port_client = PortClient(
256
- MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock()
258
+ MagicMock(),
259
+ MagicMock(),
260
+ MagicMock(),
261
+ MagicMock(),
262
+ MagicMock(),
263
+ MagicMock(),
264
+ MagicMock(),
257
265
  )
258
266
  mock_port_client.auth = AsyncMock()
259
267
  mock_port_client.auth.headers = AsyncMock(
@@ -340,10 +348,11 @@ async def test_parse_raw_event_results_to_entities_creation(
340
348
  calculation_result
341
349
  )
342
350
 
343
- entities_to_create, entities_to_delete = (
344
- await mock_live_events_mixin._parse_raw_event_results_to_entities(
345
- [one_webhook_event_raw_results_for_creation]
346
- )
351
+ (
352
+ entities_to_create,
353
+ entities_to_delete,
354
+ ) = await mock_live_events_mixin._parse_raw_event_results_to_entities(
355
+ [one_webhook_event_raw_results_for_creation]
347
356
  )
348
357
 
349
358
  assert entities_to_create == [entity]
@@ -367,10 +376,11 @@ async def test_parse_raw_event_results_to_entities_deletion(
367
376
  calculation_result
368
377
  )
369
378
 
370
- entities_to_create, entities_to_delete = (
371
- await mock_live_events_mixin._parse_raw_event_results_to_entities(
372
- [one_webhook_event_raw_results_for_deletion]
373
- )
379
+ (
380
+ entities_to_create,
381
+ entities_to_delete,
382
+ ) = await mock_live_events_mixin._parse_raw_event_results_to_entities(
383
+ [one_webhook_event_raw_results_for_deletion]
374
384
  )
375
385
 
376
386
  assert entities_to_create == []