port-ocean 0.12.2.dev14__tar.gz → 0.12.2.dev17__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.

Potentially problematic release.


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

Files changed (150) hide show
  1. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/PKG-INFO +1 -2
  2. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/list_integrations.py +5 -8
  3. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/pull.py +16 -20
  4. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/authentication.py +13 -12
  5. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/client.py +8 -9
  6. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/mixins/blueprints.py +14 -14
  7. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/mixins/entities.py +8 -7
  8. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/mixins/integrations.py +11 -11
  9. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/mixins/migrations.py +5 -5
  10. port_ocean-0.12.2.dev17/port_ocean/clients/port/retry_transport.py +51 -0
  11. port_ocean-0.12.2.dev17/port_ocean/clients/port/utils.py +67 -0
  12. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/defaults/clean.py +3 -3
  13. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/defaults/common.py +3 -3
  14. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/defaults/initialize.py +47 -48
  15. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/mixins/sync_raw.py +3 -3
  16. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/utils.py +3 -4
  17. port_ocean-0.12.2.dev17/port_ocean/helpers/async_client.py +53 -0
  18. port_ocean-0.12.2.dev17/port_ocean/helpers/retry.py +350 -0
  19. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/ocean.py +22 -20
  20. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/run.py +3 -3
  21. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/clients/port/mixins/test_entities.py +4 -3
  22. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/test_smoke.py +3 -3
  23. port_ocean-0.12.2.dev17/port_ocean/utils/async_http.py +29 -0
  24. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/repeat.py +2 -6
  25. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/signal.py +2 -1
  26. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/pyproject.toml +1 -2
  27. port_ocean-0.12.2.dev14/port_ocean/clients/port/retry_transport.py +0 -29
  28. port_ocean-0.12.2.dev14/port_ocean/clients/port/utils.py +0 -76
  29. port_ocean-0.12.2.dev14/port_ocean/helpers/retry.py +0 -200
  30. port_ocean-0.12.2.dev14/port_ocean/utils/async_http.py +0 -34
  31. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/LICENSE.md +0 -0
  32. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/README.md +0 -0
  33. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/__init__.py +0 -0
  34. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/bootstrap.py +0 -0
  35. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/__init__.py +0 -0
  36. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cli.py +0 -0
  37. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/__init__.py +0 -0
  38. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  39. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/defaults/clean.py +0 -0
  40. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/defaults/dock.py +0 -0
  41. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/defaults/group.py +0 -0
  42. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/main.py +0 -0
  43. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/new.py +0 -0
  44. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/sail.py +0 -0
  45. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/commands/version.py +0 -0
  46. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  47. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  48. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  49. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  50. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore +0 -0
  51. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  52. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  53. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  54. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  55. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  56. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  57. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  58. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  59. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile +0 -0
  60. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  61. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  62. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  63. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  64. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  65. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  66. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  67. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  68. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  69. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/cli/utils.py +0 -0
  70. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/__init__.py +0 -0
  71. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/__init__.py +0 -0
  72. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/mixins/__init__.py +0 -0
  73. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/clients/port/types.py +0 -0
  74. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/config/__init__.py +0 -0
  75. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/config/base.py +0 -0
  76. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/config/dynamic.py +0 -0
  77. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/config/settings.py +0 -0
  78. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/consumers/__init__.py +0 -0
  79. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/consumers/kafka_consumer.py +0 -0
  80. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/context/__init__.py +0 -0
  81. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/context/event.py +0 -0
  82. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/context/ocean.py +0 -0
  83. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/context/resource.py +0 -0
  84. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/__init__.py +0 -0
  85. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/defaults/__init__.py +0 -0
  86. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/event_listener/__init__.py +0 -0
  87. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/event_listener/base.py +0 -0
  88. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/event_listener/factory.py +0 -0
  89. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/event_listener/http.py +0 -0
  90. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/event_listener/kafka.py +0 -0
  91. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/event_listener/once.py +0 -0
  92. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/event_listener/polling.py +0 -0
  93. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/__init__.py +0 -0
  94. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/base.py +0 -0
  95. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  96. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  97. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  98. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  99. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  100. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  101. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  102. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  103. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  104. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  105. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  106. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  107. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  108. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  109. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
  110. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/__init__.py +0 -0
  111. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/base.py +0 -0
  112. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  113. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/mixins/events.py +0 -0
  114. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/mixins/handler.py +0 -0
  115. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/mixins/sync.py +0 -0
  116. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/integrations/mixins/utils.py +0 -0
  117. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/models.py +0 -0
  118. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/core/ocean_types.py +0 -0
  119. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/__init__.py +0 -0
  120. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/api.py +0 -0
  121. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/base.py +0 -0
  122. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/clients.py +0 -0
  123. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/context.py +0 -0
  124. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/core.py +0 -0
  125. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/port_defaults.py +0 -0
  126. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/exceptions/utils.py +0 -0
  127. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/helpers/__init__.py +0 -0
  128. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/log/__init__.py +0 -0
  129. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/log/handlers.py +0 -0
  130. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/log/logger_setup.py +0 -0
  131. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/log/sensetive.py +0 -0
  132. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/middlewares.py +0 -0
  133. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/py.typed +0 -0
  134. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/sonar-project.properties +0 -0
  135. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/__init__.py +0 -0
  136. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/conftest.py +0 -0
  137. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  138. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/helpers/__init__.py +0 -0
  139. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/helpers/fixtures.py +0 -0
  140. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/helpers/integration.py +0 -0
  141. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/helpers/ocean_app.py +0 -0
  142. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/helpers/port_client.py +0 -0
  143. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/tests/helpers/smoke_test.py +0 -0
  144. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/__init__.py +0 -0
  145. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/async_iterators.py +0 -0
  146. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/cache.py +0 -0
  147. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/misc.py +0 -0
  148. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/queue_utils.py +0 -0
  149. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/utils/time.py +0 -0
  150. {port_ocean-0.12.2.dev14 → port_ocean-0.12.2.dev17}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.12.2.dev14
3
+ Version: 0.12.2.dev17
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
@@ -22,7 +22,6 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
23
  Classifier: Topic :: Utilities
24
24
  Provides-Extra: cli
25
- Requires-Dist: aiohttp (>=3.10.10,<4.0.0)
26
25
  Requires-Dist: aiostream (>=0.5.2,<0.7.0)
27
26
  Requires-Dist: click (>=8.1.3,<9.0.0) ; extra == "cli"
28
27
  Requires-Dist: confluent-kafka (>=2.1.1,<3.0.0)
@@ -1,7 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- import asyncio
3
-
4
- import aiohttp
2
+ import httpx
5
3
 
6
4
  from port_ocean.cli.commands.main import cli_start, console
7
5
 
@@ -11,17 +9,16 @@ def list_git_folders(owner: str, repo_name: str, path: str) -> list[str]:
11
9
  api_url = f"https://api.github.com/repos/{owner}/{repo_name}/contents/{path}"
12
10
 
13
11
  # Send a GET request to the API
14
- response = asyncio.run(aiohttp.ClientSession().get(api_url))
12
+ response = httpx.get(api_url)
15
13
 
16
14
  # Check if the request was successful
17
- if not response.ok:
18
- text = asyncio.run(response.text())
15
+ if response.is_error:
19
16
  console.print(
20
- f"[bold red]Failed to list folders.[/bold red] Status Code: {response.status}, Error: {text}"
17
+ f"[bold red]Failed to list folders.[/bold red] Status Code: {response.status_code}, Error: {response.text}"
21
18
  )
22
19
  exit(1)
23
20
 
24
- contents = await response.json()
21
+ contents = response.json()
25
22
  folders = [item["name"] for item in contents if item["type"] == "dir"]
26
23
  return folders
27
24
 
@@ -1,26 +1,26 @@
1
- import asyncio
2
1
  import os
2
+ import shutil
3
+ from io import BytesIO
3
4
 
4
- import aiohttp
5
5
  import click
6
+ import httpx
6
7
 
7
8
  from port_ocean.cli.commands.main import cli_start, console
8
9
 
9
10
 
10
11
  def download_github_folder(
11
- owner: str, repo_name: str, folder_path: str, destination_path: str
12
+ owner: str, repo_name: str, folder_path: str, destination_path: str
12
13
  ) -> None:
13
14
  # Construct the API URL to get the contents of the folder
14
15
  api_url = f"https://api.github.com/repos/{owner}/{repo_name}/contents/{folder_path}"
15
16
 
16
17
  # Send a GET request to the API
17
- response = asyncio.run(aiohttp.ClientSession().request("GET", api_url))
18
+ response = httpx.get(api_url)
18
19
 
19
20
  # Check if the request was successful
20
21
  if response.is_error:
21
- text = asyncio.run(response.text())
22
22
  console.print(
23
- f"[bold red]Failed to download the folder `{folder_path}`.[/bold red] Status Code: {response.status}, Error: {text}"
23
+ f"[bold red]Failed to download the folder `{folder_path}`.[/bold red] Status Code: {response.status_code}, Error: {response.text}"
24
24
  )
25
25
  exit(1)
26
26
 
@@ -28,27 +28,23 @@ def download_github_folder(
28
28
  if not os.path.exists(destination_path):
29
29
  os.makedirs(destination_path)
30
30
 
31
- async def read_async():
32
- async with aiohttp.ClientSession().request("GET", file_url) as file_response:
33
- if file_response.status == 200:
34
- with open(file_name, "wb") as file:
35
- file.write(await file_response.read())
36
- else:
37
- text = asyncio.run(file_response.text())
38
- console.print(
39
- f"[bold red]Failed to download file `{content['name']}`.[/bold red] Status code: {file_response.status}, Error: {text}"
40
- )
41
- exit(1)
42
-
43
31
  # Iterate over the files and download them
44
- repo_contents = await response.json()
32
+ repo_contents = response.json()
45
33
  for content in repo_contents:
46
34
  if content["type"] == "file":
47
35
  file_url = content["download_url"]
48
36
  file_name = os.path.join(destination_path, content["name"])
49
37
 
50
38
  # Download the file
51
- asyncio.run(read_async())
39
+ with httpx.stream("GET", file_url) as file_response:
40
+ if file_response.status_code == 200:
41
+ with open(file_name, "wb") as file:
42
+ shutil.copyfileobj(BytesIO(file_response.content), file)
43
+ else:
44
+ console.print(
45
+ f"[bold red]Failed to download file `{content['name']}`.[/bold red] Status code: {file_response.status_code}, Error: {file_response.text}"
46
+ )
47
+ exit(1)
52
48
 
53
49
  console.print(f"Folder `{folder_path}` downloaded successfully!")
54
50
 
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- from aiohttp import ClientSession
3
+ import httpx
4
4
  from loguru import logger
5
5
  from pydantic import BaseModel, Field, PrivateAttr
6
6
 
@@ -26,14 +26,14 @@ class TokenResponse(BaseModel):
26
26
 
27
27
  class PortAuthentication:
28
28
  def __init__(
29
- self,
30
- client: ClientSession,
31
- client_id: str,
32
- client_secret: str,
33
- api_url: str,
34
- integration_identifier: str,
35
- integration_type: str,
36
- integration_version: str,
29
+ self,
30
+ client: httpx.AsyncClient,
31
+ client_id: str,
32
+ client_secret: str,
33
+ api_url: str,
34
+ integration_identifier: str,
35
+ integration_type: str,
36
+ integration_version: str,
37
37
  ):
38
38
  self.client = client
39
39
  self.api_url = api_url
@@ -51,9 +51,10 @@ class PortAuthentication:
51
51
  response = await self.client.post(
52
52
  f"{self.api_url}/auth/access_token",
53
53
  json=credentials,
54
+ extensions={"retryable": True},
54
55
  )
55
- await handle_status_code(response)
56
- return TokenResponse(**(await response.json()))
56
+ handle_status_code(response)
57
+ return TokenResponse(**response.json())
57
58
 
58
59
  def user_agent(self, user_agent_type: UserAgentType | None = None) -> str:
59
60
  user_agent = f"port-ocean/{self.integration_type}/{self.integration_version}/{self.integration_identifier}"
@@ -63,7 +64,7 @@ class PortAuthentication:
63
64
  return user_agent
64
65
 
65
66
  async def headers(
66
- self, user_agent_type: UserAgentType | None = None
67
+ self, user_agent_type: UserAgentType | None = None
67
68
  ) -> dict[Any, Any]:
68
69
  return {
69
70
  "Authorization": await self.token,
@@ -1,5 +1,3 @@
1
- from typing import Any
2
-
3
1
  from loguru import logger
4
2
 
5
3
  from port_ocean.clients.port.authentication import PortAuthentication
@@ -15,6 +13,7 @@ from port_ocean.clients.port.utils import (
15
13
  get_internal_http_client,
16
14
  )
17
15
  from port_ocean.exceptions.clients import KafkaCredentialsNotFound
16
+ from typing import Any
18
17
 
19
18
 
20
19
  class PortClient(
@@ -57,9 +56,9 @@ class PortClient(
57
56
  )
58
57
  if response.is_error:
59
58
  logger.error("Error getting kafka credentials")
60
- await handle_status_code(response)
59
+ handle_status_code(response)
61
60
 
62
- credentials = (await response.json()).get("credentials")
61
+ credentials = response.json().get("credentials")
63
62
 
64
63
  if credentials is None:
65
64
  raise KafkaCredentialsNotFound("No kafka credentials found")
@@ -73,10 +72,10 @@ class PortClient(
73
72
  f"{self.api_url}/organization", headers=await self.auth.headers()
74
73
  )
75
74
  if response.is_error:
76
- logger.error(f"Error getting organization id, error: {await response.text()}")
77
- await handle_status_code(response)
75
+ logger.error(f"Error getting organization id, error: {response.text}")
76
+ handle_status_code(response)
78
77
 
79
- return (await response.json())["organization"]["id"]
78
+ return response.json()["organization"]["id"]
80
79
 
81
80
  async def update_integration_state(
82
81
  self, state: dict[str, Any], should_raise: bool = True, should_log: bool = True
@@ -88,8 +87,8 @@ class PortClient(
88
87
  headers=await self.auth.headers(),
89
88
  json=state,
90
89
  )
91
- await handle_status_code(response, should_raise, should_log)
90
+ handle_status_code(response, should_raise, should_log)
92
91
  if response.is_success and should_log:
93
92
  logger.info("Integration resync state updated successfully")
94
93
 
95
- return (await response.json()).get("integration", {})
94
+ return response.json().get("integration", {})
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- import aiohttp
3
+ import httpx
4
4
  from loguru import logger
5
5
 
6
6
  from port_ocean.clients.port.authentication import PortAuthentication
@@ -10,7 +10,7 @@ from port_ocean.core.models import Blueprint
10
10
 
11
11
 
12
12
  class BlueprintClientMixin:
13
- def __init__(self, auth: PortAuthentication, client: aiohttp.ClientSession):
13
+ def __init__(self, auth: PortAuthentication, client: httpx.AsyncClient):
14
14
  self.auth = auth
15
15
  self.client = client
16
16
 
@@ -22,8 +22,8 @@ class BlueprintClientMixin:
22
22
  f"{self.auth.api_url}/blueprints/{identifier}",
23
23
  headers=await self.auth.headers(),
24
24
  )
25
- await handle_status_code(response, should_log=should_log)
26
- return Blueprint.parse_obj((await response.json())["blueprint"])
25
+ handle_status_code(response, should_log=should_log)
26
+ return Blueprint.parse_obj(response.json()["blueprint"])
27
27
 
28
28
  async def create_blueprint(
29
29
  self,
@@ -35,8 +35,8 @@ class BlueprintClientMixin:
35
35
  response = await self.client.post(
36
36
  f"{self.auth.api_url}/blueprints", headers=headers, json=raw_blueprint
37
37
  )
38
- await handle_status_code(response)
39
- return (await response.json())["blueprint"]
38
+ handle_status_code(response)
39
+ return response.json()["blueprint"]
40
40
 
41
41
  async def patch_blueprint(
42
42
  self,
@@ -51,7 +51,7 @@ class BlueprintClientMixin:
51
51
  headers=headers,
52
52
  json=raw_blueprint,
53
53
  )
54
- await handle_status_code(response)
54
+ handle_status_code(response)
55
55
 
56
56
  async def delete_blueprint(
57
57
  self,
@@ -70,7 +70,7 @@ class BlueprintClientMixin:
70
70
  f"{self.auth.api_url}/blueprints/{identifier}",
71
71
  headers=headers,
72
72
  )
73
- await handle_status_code(response, should_raise)
73
+ handle_status_code(response, should_raise)
74
74
  return None
75
75
  else:
76
76
  response = await self.client.delete(
@@ -78,8 +78,8 @@ class BlueprintClientMixin:
78
78
  headers=await self.auth.headers(),
79
79
  )
80
80
 
81
- await handle_status_code(response, should_raise)
82
- return (await response.json()).get("migrationId", "")
81
+ handle_status_code(response, should_raise)
82
+ return response.json().get("migrationId", "")
83
83
 
84
84
  async def create_action(
85
85
  self, action: dict[str, Any], should_log: bool = True
@@ -91,7 +91,7 @@ class BlueprintClientMixin:
91
91
  headers=await self.auth.headers(),
92
92
  )
93
93
 
94
- await handle_status_code(response, should_log=should_log)
94
+ handle_status_code(response, should_log=should_log)
95
95
 
96
96
  async def create_scorecard(
97
97
  self,
@@ -106,7 +106,7 @@ class BlueprintClientMixin:
106
106
  headers=await self.auth.headers(),
107
107
  )
108
108
 
109
- await handle_status_code(response, should_log=should_log)
109
+ handle_status_code(response, should_log=should_log)
110
110
 
111
111
  async def create_page(
112
112
  self, page: dict[str, Any], should_log: bool = True
@@ -118,7 +118,7 @@ class BlueprintClientMixin:
118
118
  headers=await self.auth.headers(),
119
119
  )
120
120
 
121
- await handle_status_code(response, should_log=should_log)
121
+ handle_status_code(response, should_log=should_log)
122
122
  return page
123
123
 
124
124
  async def delete_page(
@@ -132,4 +132,4 @@ class BlueprintClientMixin:
132
132
  headers=await self.auth.headers(),
133
133
  )
134
134
 
135
- await handle_status_code(response, should_raise)
135
+ handle_status_code(response, should_raise)
@@ -2,7 +2,7 @@ import asyncio
2
2
  from typing import Any
3
3
  from urllib.parse import quote_plus
4
4
 
5
- import aiohttp
5
+ import httpx
6
6
  from loguru import logger
7
7
 
8
8
  from port_ocean.clients.port.authentication import PortAuthentication
@@ -15,7 +15,7 @@ from port_ocean.core.models import Entity
15
15
 
16
16
 
17
17
  class EntityClientMixin:
18
- def __init__(self, auth: PortAuthentication, client: aiohttp.ClientSession):
18
+ def __init__(self, auth: PortAuthentication, client: httpx.AsyncClient):
19
19
  self.auth = auth
20
20
  self.client = client
21
21
  # Semaphore is used to limit the number of concurrent requests to port, to avoid overloading it.
@@ -56,8 +56,8 @@ class EntityClientMixin:
56
56
  f"entity: {entity.identifier} of "
57
57
  f"blueprint: {entity.blueprint}"
58
58
  )
59
- await handle_status_code(response, should_raise)
60
- result = await response.json()
59
+ handle_status_code(response, should_raise)
60
+ result = response.json()
61
61
 
62
62
  result_entity = (
63
63
  Entity.parse_obj(result["entity"]) if result.get("entity") else entity
@@ -149,7 +149,7 @@ class EntityClientMixin:
149
149
  f"blueprint: {entity.blueprint}"
150
150
  )
151
151
 
152
- await handle_status_code(response, should_raise)
152
+ handle_status_code(response, should_raise)
153
153
 
154
154
  async def batch_delete_entities(
155
155
  self,
@@ -204,10 +204,11 @@ class EntityClientMixin:
204
204
  "exclude_calculated_properties": "true",
205
205
  "include": ["blueprint", "identifier"],
206
206
  },
207
+ extensions={"retryable": True},
207
208
  timeout=30,
208
209
  )
209
- await handle_status_code(response)
210
- return [Entity.parse_obj(result) for result in (await response.json())["entities"]]
210
+ handle_status_code(response)
211
+ return [Entity.parse_obj(result) for result in response.json()["entities"]]
211
212
 
212
213
  async def search_batch_entities(
213
214
  self, user_agent_type: UserAgentType, entities_to_search: list[Entity]
@@ -1,7 +1,7 @@
1
1
  from typing import Any, TYPE_CHECKING, Optional, TypedDict
2
2
  from urllib.parse import quote_plus
3
3
 
4
- import aiohttp
4
+ import httpx
5
5
  from loguru import logger
6
6
 
7
7
  from port_ocean.clients.port.authentication import PortAuthentication
@@ -22,7 +22,7 @@ class IntegrationClientMixin:
22
22
  integration_identifier: str,
23
23
  integration_version: str,
24
24
  auth: PortAuthentication,
25
- client: aiohttp.ClientSession,
25
+ client: httpx.AsyncClient,
26
26
  ):
27
27
  self.integration_identifier = integration_identifier
28
28
  self.integration_version = integration_version
@@ -30,7 +30,7 @@ class IntegrationClientMixin:
30
30
  self.client = client
31
31
  self._log_attributes: LogAttributes | None = None
32
32
 
33
- async def _get_current_integration(self) -> aiohttp.ClientResponse:
33
+ async def _get_current_integration(self) -> httpx.Response:
34
34
  logger.info(f"Fetching integration with id: {self.integration_identifier}")
35
35
  response = await self.client.get(
36
36
  f"{self.auth.api_url}/integration/{self.integration_identifier}",
@@ -42,8 +42,8 @@ class IntegrationClientMixin:
42
42
  self, should_raise: bool = True, should_log: bool = True
43
43
  ) -> dict[str, Any]:
44
44
  response = await self._get_current_integration()
45
- await handle_status_code(response, should_raise, should_log)
46
- return (await response.json()).get("integration", {})
45
+ handle_status_code(response, should_raise, should_log)
46
+ return response.json().get("integration", {})
47
47
 
48
48
  async def get_log_attributes(self) -> LogAttributes:
49
49
  if self._log_attributes is None:
@@ -71,8 +71,8 @@ class IntegrationClientMixin:
71
71
  response = await self.client.post(
72
72
  f"{self.auth.api_url}/integration", headers=headers, json=json
73
73
  )
74
- await handle_status_code(response)
75
- return (await response.json())["integration"]
74
+ handle_status_code(response)
75
+ return response.json()["integration"]
76
76
 
77
77
  async def patch_integration(
78
78
  self,
@@ -96,8 +96,8 @@ class IntegrationClientMixin:
96
96
  headers=headers,
97
97
  json=json,
98
98
  )
99
- await handle_status_code(response)
100
- return (await response.json())["integration"]
99
+ handle_status_code(response)
100
+ return response.json()["integration"]
101
101
 
102
102
  async def ingest_integration_logs(self, logs: list[dict[str, Any]]) -> None:
103
103
  logger.debug("Ingesting logs")
@@ -110,7 +110,7 @@ class IntegrationClientMixin:
110
110
  "logs": logs,
111
111
  },
112
112
  )
113
- await handle_status_code(response, should_log=False)
113
+ handle_status_code(response, should_log=False)
114
114
  logger.debug("Logs successfully ingested")
115
115
 
116
116
  async def ingest_integration_kind_examples(
@@ -125,5 +125,5 @@ class IntegrationClientMixin:
125
125
  "examples": sensitive_log_filter.mask_object(data, full_hide=True),
126
126
  },
127
127
  )
128
- await handle_status_code(response, should_log=should_log)
128
+ handle_status_code(response, should_log=should_log)
129
129
  logger.debug(f"Examples for kind {kind} successfully ingested")
@@ -1,6 +1,6 @@
1
1
  import asyncio
2
2
 
3
- import aiohttp
3
+ import httpx
4
4
  from loguru import logger
5
5
 
6
6
  from port_ocean.clients.port.authentication import PortAuthentication
@@ -9,7 +9,7 @@ from port_ocean.core.models import Migration
9
9
 
10
10
 
11
11
  class MigrationClientMixin:
12
- def __init__(self, auth: PortAuthentication, client: aiohttp.ClientSession):
12
+ def __init__(self, auth: PortAuthentication, client: httpx.AsyncClient):
13
13
  self.auth = auth
14
14
  self.client = client
15
15
 
@@ -28,9 +28,9 @@ class MigrationClientMixin:
28
28
  headers=headers,
29
29
  )
30
30
 
31
- await handle_status_code(response, should_raise=True)
31
+ handle_status_code(response, should_raise=True)
32
32
 
33
- migration_status = (await response.json()).get("migration", {}).get("status", None)
33
+ migration_status = response.json().get("migration", {}).get("status", None)
34
34
  if (
35
35
  migration_status == "RUNNING"
36
36
  or migration_status == "INITIALIZING"
@@ -43,4 +43,4 @@ class MigrationClientMixin:
43
43
  f"Migration with id: {migration_id} finished with status {migration_status}",
44
44
  )
45
45
 
46
- return Migration.parse_obj(await response.json()["migration"])
46
+ return Migration.parse_obj(response.json()["migration"])
@@ -0,0 +1,51 @@
1
+ import asyncio
2
+ from http import HTTPStatus
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ import httpx
6
+
7
+ from port_ocean.helpers.retry import RetryTransport
8
+
9
+ if TYPE_CHECKING:
10
+ from port_ocean.clients.port.client import PortClient
11
+
12
+
13
+ class TokenRetryTransport(RetryTransport):
14
+ def __init__(self, port_client: "PortClient", **kwargs: Any) -> None:
15
+ super().__init__(**kwargs)
16
+ self.port_client = port_client
17
+
18
+ async def _handle_unauthorized(self, response: httpx.Response) -> None:
19
+ token = await self.port_client.auth.token
20
+ response.headers["Authorization"] = f"Bearer {token}"
21
+
22
+ def is_token_error(self, response: httpx.Response) -> bool:
23
+ return (
24
+ response.status_code == HTTPStatus.UNAUTHORIZED
25
+ and "/auth/access_token" not in str(response.request.url)
26
+ and self.port_client.auth.last_token_object is not None
27
+ and self.port_client.auth.last_token_object.expired
28
+ )
29
+
30
+ async def _should_retry_async(self, response: httpx.Response) -> bool:
31
+ if self.is_token_error(response):
32
+ if self._logger:
33
+ self._logger.info(
34
+ "Got unauthorized response, trying to refresh token before retrying"
35
+ )
36
+ await self._handle_unauthorized(response)
37
+ return True
38
+ return await super()._should_retry_async(response)
39
+
40
+ def _should_retry(self, response: httpx.Response) -> bool:
41
+ if self.is_token_error(response):
42
+ if self._logger:
43
+ self._logger.info(
44
+ "Got unauthorized response, trying to refresh token before retrying"
45
+ )
46
+ asyncio.get_running_loop().run_until_complete(
47
+ self._handle_unauthorized(response)
48
+ )
49
+
50
+ return True
51
+ return super()._should_retry(response)
@@ -0,0 +1,67 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ import httpx
4
+ from loguru import logger
5
+ from werkzeug.local import LocalStack, LocalProxy
6
+
7
+ from port_ocean.clients.port.retry_transport import TokenRetryTransport
8
+ from port_ocean.helpers.async_client import OceanAsyncClient
9
+
10
+ if TYPE_CHECKING:
11
+ from port_ocean.clients.port.client import PortClient
12
+
13
+ # In case the framework sends more requests to port in parallel than allowed by the limits, a PoolTimeout exception will
14
+ # be raised.
15
+ # Raising defaults for the timeout, in addition to the limits, will allow request to wait for a connection for a longer
16
+ # period of time, before raising an exception.
17
+ # The max_connections value can't be too high, as it will cause the application to run out of memory.
18
+ # The max_keepalive_connections can't be too high, as it will cause the application to run out of available connections.
19
+ PORT_HTTP_MAX_CONNECTIONS_LIMIT = 200
20
+ PORT_HTTP_MAX_KEEP_ALIVE_CONNECTIONS = 50
21
+ PORT_HTTP_TIMEOUT = 60.0
22
+
23
+ PORT_HTTPX_TIMEOUT = httpx.Timeout(PORT_HTTP_TIMEOUT)
24
+ PORT_HTTPX_LIMITS = httpx.Limits(
25
+ max_connections=PORT_HTTP_MAX_CONNECTIONS_LIMIT,
26
+ max_keepalive_connections=PORT_HTTP_MAX_KEEP_ALIVE_CONNECTIONS,
27
+ )
28
+
29
+ _http_client: LocalStack[httpx.AsyncClient] = LocalStack()
30
+
31
+
32
+ def _get_http_client_context(port_client: "PortClient") -> httpx.AsyncClient:
33
+ client = _http_client.top
34
+ if client is None:
35
+ client = OceanAsyncClient(
36
+ TokenRetryTransport,
37
+ transport_kwargs={"port_client": port_client},
38
+ timeout=PORT_HTTPX_TIMEOUT,
39
+ limits=PORT_HTTPX_LIMITS,
40
+ )
41
+ _http_client.push(client)
42
+
43
+ return client
44
+
45
+
46
+ _port_internal_async_client: httpx.AsyncClient = None # type: ignore
47
+
48
+
49
+ def get_internal_http_client(port_client: "PortClient") -> httpx.AsyncClient:
50
+ global _port_internal_async_client
51
+ if _port_internal_async_client is None:
52
+ _port_internal_async_client = LocalProxy(
53
+ lambda: _get_http_client_context(port_client)
54
+ )
55
+
56
+ return _port_internal_async_client
57
+
58
+
59
+ def handle_status_code(
60
+ response: httpx.Response, should_raise: bool = True, should_log: bool = True
61
+ ) -> None:
62
+ if should_log and response.is_error:
63
+ logger.error(
64
+ f"Request failed with status code: {response.status_code}, Error: {response.text}"
65
+ )
66
+ if should_raise:
67
+ response.raise_for_status()
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  from typing import Type
3
3
 
4
- import aiohttp
4
+ import httpx
5
5
  from loguru import logger
6
6
 
7
7
  from port_ocean.context.ocean import ocean
@@ -66,6 +66,6 @@ async def _clean_defaults(
66
66
  for migration_id in migration_ids
67
67
  )
68
68
  )
69
- except aiohttp.ClientResponseError as e:
70
- logger.error(f"Failed to delete blueprints: {e.message}.")
69
+ except httpx.HTTPStatusError as e:
70
+ logger.error(f"Failed to delete blueprints: {e.response.text}.")
71
71
  raise e
@@ -2,7 +2,7 @@ import json
2
2
  from pathlib import Path
3
3
  from typing import Type, Any, TypedDict, Optional
4
4
 
5
- import aiohttp
5
+ import httpx
6
6
  import yaml
7
7
  from pydantic import BaseModel, Field
8
8
  from starlette import status
@@ -39,8 +39,8 @@ async def is_integration_exists(port_client: PortClient) -> bool:
39
39
  try:
40
40
  await port_client.get_current_integration(should_log=False)
41
41
  return True
42
- except aiohttp.ClientResponseError as e:
43
- if e.status != status.HTTP_404_NOT_FOUND:
42
+ except httpx.HTTPStatusError as e:
43
+ if e.response.status_code != status.HTTP_404_NOT_FOUND:
44
44
  raise e
45
45
 
46
46
  return False