port-ocean 0.23.3__tar.gz → 0.23.4__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 (207) hide show
  1. {port_ocean-0.23.3 → port_ocean-0.23.4}/PKG-INFO +1 -1
  2. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/integrations.py +3 -2
  3. port_ocean-0.23.4/port_ocean/context/metric_resource.py +63 -0
  4. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/resync_state_updater/updater.py +3 -3
  5. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/sync_raw.py +106 -63
  6. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/helpers/metric/metric.py +32 -10
  7. port_ocean-0.23.4/port_ocean/helpers/metric/utils.py +52 -0
  8. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +29 -5
  9. {port_ocean-0.23.3 → port_ocean-0.23.4}/pyproject.toml +1 -1
  10. port_ocean-0.23.3/port_ocean/helpers/metric/utils.py +0 -28
  11. {port_ocean-0.23.3 → port_ocean-0.23.4}/LICENSE.md +0 -0
  12. {port_ocean-0.23.3 → port_ocean-0.23.4}/README.md +0 -0
  13. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.Deb +0 -0
  14. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.alpine +0 -0
  15. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.base.builder +0 -0
  16. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.base.runner +0 -0
  17. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.dockerignore +0 -0
  18. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.local +0 -0
  19. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Makefile +0 -0
  20. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/entry_local.sh +0 -0
  21. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/grpcio.sh +0 -0
  22. {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/init.sh +0 -0
  23. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/__init__.py +0 -0
  24. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/bootstrap.py +0 -0
  25. {port_ocean-0.23.3/port_ocean/tests/helpers → port_ocean-0.23.4/port_ocean/cache}/__init__.py +0 -0
  26. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/base.py +0 -0
  27. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/disk.py +0 -0
  28. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/errors.py +0 -0
  29. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/memory.py +0 -0
  30. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/__init__.py +0 -0
  31. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cli.py +0 -0
  32. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/__init__.py +0 -0
  33. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  34. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/clean.py +0 -0
  35. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/dock.py +0 -0
  36. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/group.py +0 -0
  37. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/list_integrations.py +0 -0
  38. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/main.py +0 -0
  39. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/new.py +0 -0
  40. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/pull.py +0 -0
  41. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/sail.py +0 -0
  42. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/version.py +0 -0
  43. {port_ocean-0.23.3/port_ocean/tests/clients/oauth → port_ocean-0.23.4/port_ocean/cli/cookiecutter}/__init__.py +0 -0
  44. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  45. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  46. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  47. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  48. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  49. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  50. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  51. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  52. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  53. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  54. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  55. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  56. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  57. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  58. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  59. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  60. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  61. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  62. {port_ocean-0.23.3/port_ocean/tests/clients → port_ocean-0.23.4/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests}/__init__.py +0 -0
  63. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  64. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/utils.py +0 -0
  65. {port_ocean-0.23.3/port_ocean/tests → port_ocean-0.23.4/port_ocean/clients}/__init__.py +0 -0
  66. {port_ocean-0.23.3/port_ocean/log → port_ocean-0.23.4/port_ocean/clients/auth}/__init__.py +0 -0
  67. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/auth/auth_client.py +0 -0
  68. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/auth/oauth_client.py +0 -0
  69. {port_ocean-0.23.3/port_ocean/helpers → port_ocean-0.23.4/port_ocean/clients/port}/__init__.py +0 -0
  70. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/authentication.py +0 -0
  71. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/client.py +0 -0
  72. {port_ocean-0.23.3/port_ocean/exceptions → port_ocean-0.23.4/port_ocean/clients/port/mixins}/__init__.py +0 -0
  73. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  74. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/entities.py +0 -0
  75. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/migrations.py +0 -0
  76. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/organization.py +0 -0
  77. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/retry_transport.py +0 -0
  78. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/types.py +0 -0
  79. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/utils.py +0 -0
  80. {port_ocean-0.23.3/port_ocean/core/integrations → port_ocean-0.23.4/port_ocean/config}/__init__.py +0 -0
  81. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/config/base.py +0 -0
  82. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/config/dynamic.py +0 -0
  83. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/config/settings.py +0 -0
  84. {port_ocean-0.23.3/port_ocean/core/handlers/webhook → port_ocean-0.23.4/port_ocean/consumers}/__init__.py +0 -0
  85. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/consumers/kafka_consumer.py +0 -0
  86. {port_ocean-0.23.3/port_ocean/core/handlers/entities_state_applier/port → port_ocean-0.23.4/port_ocean/context}/__init__.py +0 -0
  87. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/context/event.py +0 -0
  88. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/context/ocean.py +0 -0
  89. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/context/resource.py +0 -0
  90. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/__init__.py +0 -0
  91. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/__init__.py +0 -0
  92. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/clean.py +0 -0
  93. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/common.py +0 -0
  94. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/initialize.py +0 -0
  95. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/__init__.py +0 -0
  96. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/base.py +0 -0
  97. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/factory.py +0 -0
  98. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/http.py +0 -0
  99. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/kafka.py +0 -0
  100. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/once.py +0 -0
  101. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/polling.py +0 -0
  102. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/webhooks_only.py +0 -0
  103. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/__init__.py +0 -0
  104. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/base.py +0 -0
  105. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  106. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  107. {port_ocean-0.23.3/port_ocean/context → port_ocean-0.23.4/port_ocean/core/handlers/entities_state_applier/port}/__init__.py +0 -0
  108. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  109. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  110. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  111. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  112. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  113. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  114. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  115. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  116. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  117. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  118. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/queue/__init__.py +0 -0
  119. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/queue/abstract_queue.py +0 -0
  120. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/queue/local_queue.py +0 -0
  121. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  122. {port_ocean-0.23.3/port_ocean/consumers → port_ocean-0.23.4/port_ocean/core/handlers/webhook}/__init__.py +0 -0
  123. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +0 -0
  124. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/webhook/processor_manager.py +0 -0
  125. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/webhook/webhook_event.py +0 -0
  126. {port_ocean-0.23.3/port_ocean/config → port_ocean-0.23.4/port_ocean/core/integrations}/__init__.py +0 -0
  127. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/base.py +0 -0
  128. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  129. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/events.py +0 -0
  130. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/handler.py +0 -0
  131. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/live_events.py +0 -0
  132. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/sync.py +0 -0
  133. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/utils.py +0 -0
  134. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/models.py +0 -0
  135. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/ocean_types.py +0 -0
  136. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
  137. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/utils/utils.py +0 -0
  138. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/debug_cli.py +0 -0
  139. {port_ocean-0.23.3/port_ocean/clients/port/mixins → port_ocean-0.23.4/port_ocean/exceptions}/__init__.py +0 -0
  140. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/api.py +0 -0
  141. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/base.py +0 -0
  142. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/clients.py +0 -0
  143. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/context.py +0 -0
  144. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/core.py +0 -0
  145. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/port_defaults.py +0 -0
  146. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/utils.py +0 -0
  147. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/webhook_processor.py +0 -0
  148. {port_ocean-0.23.3/port_ocean/clients/port → port_ocean-0.23.4/port_ocean/helpers}/__init__.py +0 -0
  149. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/helpers/async_client.py +0 -0
  150. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/helpers/retry.py +0 -0
  151. {port_ocean-0.23.3/port_ocean/clients/auth → port_ocean-0.23.4/port_ocean/log}/__init__.py +0 -0
  152. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/log/handlers.py +0 -0
  153. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/log/logger_setup.py +0 -0
  154. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/log/sensetive.py +0 -0
  155. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/middlewares.py +0 -0
  156. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/ocean.py +0 -0
  157. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/py.typed +0 -0
  158. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/run.py +0 -0
  159. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/sonar-project.properties +0 -0
  160. {port_ocean-0.23.3/port_ocean/clients → port_ocean-0.23.4/port_ocean/tests}/__init__.py +0 -0
  161. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/cache/__init__.py +0 -0
  162. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/cache/test_disk_cache.py +0 -0
  163. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/cache/test_memory_cache.py +0 -0
  164. {port_ocean-0.23.3/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests → port_ocean-0.23.4/port_ocean/tests/clients}/__init__.py +0 -0
  165. {port_ocean-0.23.3/port_ocean/cli/cookiecutter → port_ocean-0.23.4/port_ocean/tests/clients/oauth}/__init__.py +0 -0
  166. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/clients/oauth/test_oauth_client.py +0 -0
  167. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
  168. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
  169. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/conftest.py +0 -0
  170. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/conftest.py +0 -0
  171. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/defaults/test_common.py +0 -0
  172. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -0
  173. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  174. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/mixins/test_live_events.py +0 -0
  175. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
  176. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/port_app_config/test_base.py +0 -0
  177. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
  178. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
  179. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +0 -0
  180. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
  181. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/test_utils.py +0 -0
  182. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
  183. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
  184. {port_ocean-0.23.3/port_ocean/cache → port_ocean-0.23.4/port_ocean/tests/helpers}/__init__.py +0 -0
  185. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/fake_port_api.py +0 -0
  186. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/fixtures.py +0 -0
  187. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/integration.py +0 -0
  188. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/ocean_app.py +0 -0
  189. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/port_client.py +0 -0
  190. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/smoke_test.py +0 -0
  191. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/log/test_handlers.py +0 -0
  192. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/test_metric.py +0 -0
  193. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/test_ocean.py +0 -0
  194. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/test_smoke.py +0 -0
  195. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/utils/test_async_iterators.py +0 -0
  196. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/utils/test_cache.py +0 -0
  197. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/__init__.py +0 -0
  198. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/async_http.py +0 -0
  199. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/async_iterators.py +0 -0
  200. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/cache.py +0 -0
  201. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/ipc.py +0 -0
  202. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/misc.py +0 -0
  203. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/queue_utils.py +0 -0
  204. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/repeat.py +0 -0
  205. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/signal.py +0 -0
  206. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/time.py +0 -0
  207. {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.23.3
3
+ Version: 0.23.4
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
@@ -214,8 +214,9 @@ class IntegrationClientMixin:
214
214
  logger.debug("starting POST metrics request", metrics=metrics)
215
215
  metrics_attributes = await self.get_metrics_attributes()
216
216
  headers = await self.auth.headers()
217
+ url = metrics_attributes["ingestUrl"] + "/syncMetrics"
217
218
  response = await self.client.post(
218
- metrics_attributes["ingestUrl"],
219
+ url,
219
220
  headers=headers,
220
221
  json={
221
222
  "syncKindsMetrics": metrics,
@@ -229,7 +230,7 @@ class IntegrationClientMixin:
229
230
  metrics_attributes = await self.get_metrics_attributes()
230
231
  url = (
231
232
  metrics_attributes["ingestUrl"]
232
- + f"/resync/{kind_metrics['eventId']}/kind/{kind_metrics['kindIdentifier']}"
233
+ + f"/syncMetrics/resync/{kind_metrics['eventId']}/kind/{kind_metrics['kindIdentifier']}"
233
234
  )
234
235
  headers = await self.auth.headers()
235
236
  response = await self.client.put(
@@ -0,0 +1,63 @@
1
+ from contextlib import asynccontextmanager
2
+ from dataclasses import dataclass
3
+ from typing import AsyncIterator, TYPE_CHECKING
4
+
5
+ from loguru import logger
6
+ from werkzeug.local import LocalStack, LocalProxy
7
+
8
+ from port_ocean.exceptions.context import (
9
+ ResourceContextNotFoundError,
10
+ )
11
+
12
+ if TYPE_CHECKING:
13
+ pass
14
+
15
+
16
+ @dataclass
17
+ class MetricResourceContext:
18
+ """
19
+ The metric resource context is a context manager that allows you to access the current metric resource if there is one.
20
+ This is useful for getting the metric resource kind
21
+ """
22
+
23
+ metric_resource_kind: str
24
+ index: int
25
+
26
+ @property
27
+ def kind(self) -> str:
28
+ return self.metric_resource_kind
29
+
30
+
31
+ _resource_context_stack: LocalStack[MetricResourceContext] = LocalStack()
32
+
33
+
34
+ def _get_metric_resource_context() -> MetricResourceContext:
35
+ """
36
+ Get the context from the current thread.
37
+ """
38
+ top_resource_context = _resource_context_stack.top
39
+ if top_resource_context is None:
40
+ raise ResourceContextNotFoundError(
41
+ "You must be inside an metric resource context in order to use it"
42
+ )
43
+
44
+ return top_resource_context
45
+
46
+
47
+ metric_resource: MetricResourceContext = LocalProxy(lambda: _get_metric_resource_context()) # type: ignore
48
+
49
+
50
+ @asynccontextmanager
51
+ async def metric_resource_context(
52
+ metric_resource_kind: str, index: int = 0
53
+ ) -> AsyncIterator[MetricResourceContext]:
54
+ _resource_context_stack.push(
55
+ MetricResourceContext(metric_resource_kind=metric_resource_kind, index=index)
56
+ )
57
+
58
+ with logger.contextualize(
59
+ metric_resource_kind=metric_resource.metric_resource_kind
60
+ ):
61
+ yield metric_resource
62
+
63
+ _resource_context_stack.pop()
@@ -94,6 +94,6 @@ class ResyncStateUpdater:
94
94
  await ocean.metrics.send_metrics_to_webhook(
95
95
  kind=ocean.metrics.current_resource_kind()
96
96
  )
97
- # await ocean.metrics.report_sync_metrics(
98
- # kinds=[ocean.metrics.current_resource_kind()]
99
- # ) # TODO: uncomment this when end points are ready
97
+ await ocean.metrics.report_sync_metrics(
98
+ kinds=[ocean.metrics.current_resource_kind()]
99
+ )
@@ -9,6 +9,7 @@ import httpx
9
9
  from loguru import logger
10
10
  from port_ocean.clients.port.types import UserAgentType
11
11
  from port_ocean.context.event import TriggerType, event_context, EventType, event
12
+ from port_ocean.context.metric_resource import metric_resource_context
12
13
  from port_ocean.context.ocean import ocean
13
14
  from port_ocean.context.resource import resource_context
14
15
  from port_ocean.context import resource
@@ -33,8 +34,8 @@ from port_ocean.core.ocean_types import (
33
34
  )
34
35
  from port_ocean.core.utils.utils import resolve_entities_diff, zip_and_sum, gather_and_split_errors_from_results
35
36
  from port_ocean.exceptions.core import OceanAbortException
36
- from port_ocean.helpers.metric.metric import SyncState, MetricType, MetricPhase
37
- from port_ocean.helpers.metric.utils import TimeMetric
37
+ from port_ocean.helpers.metric.metric import MetricResourceKind, SyncState, MetricType, MetricPhase
38
+ from port_ocean.helpers.metric.utils import TimeMetric, TimeMetricWithResourceKind
38
39
  from port_ocean.utils.ipc import FileIPC
39
40
 
40
41
  SEND_RAW_DATA_EXAMPLES_AMOUNT = 5
@@ -249,9 +250,16 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
249
250
  labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
250
251
  value=len(objects_diff[0].entity_selector_diff.passed) - len(changed_entities)
251
252
  )
252
- await self.entities_state_applier.upsert(
253
+ upserted_entities = await self.entities_state_applier.upsert(
253
254
  changed_entities, user_agent_type
254
255
  )
256
+
257
+ ocean.metrics.set_metric(
258
+ name=MetricType.OBJECT_COUNT_NAME,
259
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
260
+ value=len(upserted_entities)
261
+ )
262
+
255
263
  else:
256
264
  logger.info("Entities in batch didn't changed since last sync, skipping", total_entities=len(objects_diff[0].entity_selector_diff.passed))
257
265
  ocean.metrics.inc_metric(
@@ -265,6 +273,11 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
265
273
  modified_objects = await self.entities_state_applier.upsert(
266
274
  objects_diff[0].entity_selector_diff.passed, user_agent_type
267
275
  )
276
+ ocean.metrics.set_metric(
277
+ name=MetricType.OBJECT_COUNT_NAME,
278
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
279
+ value=len(upserted_entities)
280
+ )
268
281
  else:
269
282
  modified_objects = await self.entities_state_applier.upsert(
270
283
  objects_diff[0].entity_selector_diff.passed, user_agent_type
@@ -633,16 +646,12 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
633
646
  async with resource_context(resource,index):
634
647
  resource_kind_id = f"{resource.kind}-{index}"
635
648
  ocean.metrics.sync_state = SyncState.SYNCING
649
+
636
650
  task = asyncio.create_task(
637
651
  self._register_in_batches(resource, user_agent_type)
638
652
  )
639
653
  event.on_abort(lambda: task.cancel())
640
654
  kind_results: tuple[list[Entity], list[Exception]] = await task
641
- ocean.metrics.set_metric(
642
- name=MetricType.OBJECT_COUNT_NAME,
643
- labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
644
- value=len(kind_results[0])
645
- )
646
655
 
647
656
  if ocean.metrics.sync_state != SyncState.FAILED:
648
657
  ocean.metrics.sync_state = SyncState.COMPLETED
@@ -650,10 +659,88 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
650
659
  await ocean.metrics.send_metrics_to_webhook(
651
660
  kind=resource_kind_id
652
661
  )
653
- # await ocean.metrics.report_kind_sync_metrics(kind=resource_kind_id) # TODO: uncomment this when end points are ready
662
+ await ocean.metrics.report_kind_sync_metrics(kind=resource_kind_id, blueprint=resource.port.entity.mappings.blueprint)
654
663
 
655
664
  return kind_results
656
665
 
666
+ @TimeMetricWithResourceKind(MetricPhase.RESYNC)
667
+ async def resync_reconciliation(
668
+ self,
669
+ creation_results: list[tuple[list[Entity], list[Exception]]],
670
+ did_fetched_current_state: bool,
671
+ user_agent_type: UserAgentType,
672
+ app_config: Any,
673
+ silent: bool = True,
674
+ ) -> None:
675
+ """Handle the reconciliation phase of the resync process.
676
+
677
+ This method handles:
678
+ 1. Sorting and upserting failed entities
679
+ 2. Checking if current state was fetched
680
+ 3. Calculating resync diff
681
+ 4. Handling errors
682
+ 5. Deleting entities that are no longer needed
683
+ 6. Executing resync complete hooks
684
+
685
+ Args:
686
+ creation_results (list[tuple[list[Entity], list[Exception]]]): Results from entity creation
687
+ did_fetched_current_state (bool): Whether the current state was successfully fetched
688
+ user_agent_type (UserAgentType): The type of user agent
689
+ app_config (Any): The application configuration
690
+ silent (bool): Whether to raise exceptions or handle them silently
691
+
692
+ """
693
+ await self.sort_and_upsert_failed_entities(user_agent_type)
694
+
695
+ if not did_fetched_current_state:
696
+ logger.warning(
697
+ "Due to an error before the resync, the previous state of entities at Port is unknown."
698
+ " Skipping delete phase due to unknown initial state."
699
+ )
700
+ return False
701
+
702
+ logger.info("Starting resync diff calculation")
703
+ generated_entities, errors = zip_and_sum(creation_results) or [
704
+ [],
705
+ [],
706
+ ]
707
+
708
+ if errors:
709
+ message = f"Resync failed with {len(errors)} errors, skipping delete phase due to incomplete state"
710
+ error_group = ExceptionGroup(
711
+ message,
712
+ errors,
713
+ )
714
+ if not silent:
715
+ raise error_group
716
+
717
+ logger.error(message, exc_info=error_group)
718
+ return False
719
+
720
+ logger.info(
721
+ f"Running resync diff calculation, number of entities created during sync: {len(generated_entities)}"
722
+ )
723
+ entities_at_port = await ocean.port_client.search_entities(
724
+ user_agent_type
725
+ )
726
+
727
+ await self.entities_state_applier.delete_diff(
728
+ {"before": entities_at_port, "after": generated_entities},
729
+ user_agent_type, app_config.get_entity_deletion_threshold()
730
+ )
731
+
732
+ logger.info("Resync finished successfully")
733
+
734
+ # Execute resync_complete hooks
735
+ if "resync_complete" in self.event_strategy:
736
+ logger.info("Executing resync_complete hooks")
737
+
738
+ for resync_complete_fn in self.event_strategy["resync_complete"]:
739
+ await resync_complete_fn()
740
+
741
+ logger.info("Finished executing resync_complete hooks")
742
+
743
+
657
744
  @TimeMetric(MetricPhase.RESYNC)
658
745
  async def sync_raw_all(
659
746
  self,
@@ -689,8 +776,9 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
689
776
  logger.info(f"Resync will use the following mappings: {app_config.dict()}")
690
777
 
691
778
  kinds = [f"{resource.kind}-{index}" for index, resource in enumerate(app_config.resources)]
779
+ blueprints = [resource.port.entity.mappings.blueprint for resource in app_config.resources]
692
780
  ocean.metrics.initialize_metrics(kinds)
693
- # await ocean.metrics.report_sync_metrics(kinds=kinds) # TODO: uncomment this when end points are ready
781
+ await ocean.metrics.report_sync_metrics(kinds=kinds, blueprints=blueprints)
694
782
 
695
783
  # Clear cache
696
784
  await ocean.app.cache_provider.clear()
@@ -716,65 +804,20 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
716
804
  multiprocessing.set_start_method('fork', True)
717
805
  try:
718
806
  for index,resource in enumerate(app_config.resources):
719
-
720
807
  logger.info(f"Starting processing resource {resource.kind} with index {index}")
721
-
722
808
  creation_results.append(await self.process_resource(resource,index,user_agent_type))
723
-
724
- await self.sort_and_upsert_failed_entities(user_agent_type)
725
-
726
809
  except asyncio.CancelledError as e:
727
810
  logger.warning("Resync aborted successfully, skipping delete phase. This leads to an incomplete state")
728
811
  raise
729
812
  else:
730
- if not did_fetched_current_state:
731
- logger.warning(
732
- "Due to an error before the resync, the previous state of entities at Port is unknown."
733
- " Skipping delete phase due to unknown initial state."
734
- )
735
- return
736
-
737
- logger.info("Starting resync diff calculation")
738
- generated_entities, errors = zip_and_sum(creation_results) or [
739
- [],
740
- [],
741
- ]
742
-
743
- if errors:
744
- message = f"Resync failed with {len(errors)} errors, skipping delete phase due to incomplete state"
745
- error_group = ExceptionGroup(
746
- message,
747
- errors,
748
- )
749
- if not silent:
750
- raise error_group
751
-
752
- logger.error(message, exc_info=error_group)
753
- return False
754
- else:
755
- logger.info(
756
- f"Running resync diff calculation, number of entities created during sync: {len(generated_entities)}"
757
- )
758
- entities_at_port = await ocean.port_client.search_entities(
759
- user_agent_type
760
- )
761
- await self.entities_state_applier.delete_diff(
762
- {"before": entities_at_port, "after": generated_entities},
763
- user_agent_type, app_config.get_entity_deletion_threshold()
764
- )
765
-
766
- logger.info("Resync finished successfully")
767
-
768
- # Execute resync_complete hooks
769
- if "resync_complete" in self.event_strategy:
770
- logger.info("Executing resync_complete hooks")
771
-
772
- for resync_complete_fn in self.event_strategy["resync_complete"]:
773
- await resync_complete_fn()
774
-
775
- logger.info("Finished executing resync_complete hooks")
776
-
777
- return True
813
+ await self.resync_reconciliation(
814
+ creation_results,
815
+ did_fetched_current_state,
816
+ user_agent_type,
817
+ app_config,
818
+ silent
819
+ )
820
+ await ocean.metrics.report_sync_metrics(kinds=[MetricResourceKind.RECONCILIATION])
778
821
  finally:
779
822
  await ocean.app.cache_provider.clear()
780
823
  if ocean.app.process_execution_mode == ProcessExecutionMode.multi_process:
@@ -6,7 +6,7 @@ import prometheus_client
6
6
  from httpx import AsyncClient
7
7
  from fastapi.responses import PlainTextResponse
8
8
  from loguru import logger
9
- from port_ocean.context import resource
9
+ from port_ocean.context import metric_resource, resource
10
10
  from prometheus_client import Gauge
11
11
  import prometheus_client.openmetrics
12
12
  import prometheus_client.openmetrics.exposition
@@ -57,6 +57,11 @@ class SyncState:
57
57
  FAILED = "failed"
58
58
 
59
59
 
60
+ class MetricResourceKind:
61
+ RECONCILIATION = "__reconciliation__"
62
+ RESYNC = "__resync__"
63
+
64
+
60
65
  # Registry for core and custom metrics
61
66
  _metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
62
67
  MetricType.DURATION_NAME: (
@@ -252,8 +257,6 @@ class Metrics:
252
257
  )
253
258
 
254
259
  def create_mertic_router(self) -> APIRouter:
255
- if not self.enabled:
256
- return APIRouter()
257
260
  router = APIRouter()
258
261
 
259
262
  @router.get("/", response_class=PlainTextResponse)
@@ -265,6 +268,12 @@ class Metrics:
265
268
  def current_resource_kind(self) -> str:
266
269
  try:
267
270
  return f"{resource.resource.kind}-{resource.resource.index}"
271
+ except ResourceContextNotFoundError:
272
+ return self.current_metric_resource_kind()
273
+
274
+ def current_metric_resource_kind(self) -> str:
275
+ try:
276
+ return metric_resource.metric_resource.metric_resource_kind
268
277
  except ResourceContextNotFoundError:
269
278
  return "__runtime__"
270
279
 
@@ -274,15 +283,21 @@ class Metrics:
274
283
  ).decode()
275
284
 
276
285
  async def report_sync_metrics(
277
- self, metric_name: Optional[str] = None, kinds: Optional[list[str]] = None
286
+ self,
287
+ metric_name: Optional[str] = None,
288
+ kinds: Optional[list[str]] = None,
289
+ blueprints: Optional[list[Optional[str]]] = None,
278
290
  ) -> None:
279
291
  if kinds is None:
280
292
  return None
281
293
 
282
294
  metrics = []
283
295
 
284
- for kind in kinds:
285
- metric = self.generate_metrics(metric_name, kind)
296
+ if blueprints is None:
297
+ blueprints = [None] * len(kinds)
298
+
299
+ for kind, blueprint in zip(kinds, blueprints):
300
+ metric = self.generate_metrics(metric_name, kind, blueprint)
286
301
  metrics.extend(metric)
287
302
 
288
303
  try:
@@ -291,9 +306,12 @@ class Metrics:
291
306
  logger.error(f"Error posting metrics: {e}", metrics=metrics)
292
307
 
293
308
  async def report_kind_sync_metrics(
294
- self, metric_name: Optional[str] = None, kind: Optional[str] = None
309
+ self,
310
+ metric_name: Optional[str] = None,
311
+ kind: Optional[str] = None,
312
+ blueprint: Optional[str] = None,
295
313
  ) -> None:
296
- metrics = self.generate_metrics(metric_name, kind)
314
+ metrics = self.generate_metrics(metric_name, kind, blueprint)
297
315
  if not metrics:
298
316
  return None
299
317
 
@@ -304,7 +322,10 @@ class Metrics:
304
322
  logger.error(f"Error putting metrics: {e}", metrics=metrics)
305
323
 
306
324
  def generate_metrics(
307
- self, metric_name: Optional[str] = None, kind: Optional[str] = None
325
+ self,
326
+ metric_name: Optional[str] = None,
327
+ kind: Optional[str] = None,
328
+ blueprint: Optional[str] = None,
308
329
  ) -> list[dict[str, Any]]:
309
330
  try:
310
331
  latest_raw = self.generate_latest()
@@ -363,9 +384,10 @@ class Metrics:
363
384
  if "-" in kind_key
364
385
  else kind_key
365
386
  ),
366
- "kindIndex": 0 if kind_key == "__runtime__" else int(kind_key[-1]),
387
+ "kindIndex": int(kind_key[-1]) if kind_key[-1].isdigit() else 0,
367
388
  "eventId": self.event_id,
368
389
  "syncState": self.sync_state,
390
+ "blueprint": blueprint if blueprint else "",
369
391
  "metrics": metrics,
370
392
  }
371
393
  events.append(event)
@@ -0,0 +1,52 @@
1
+ from functools import wraps
2
+ import time
3
+ from typing import Any, Callable
4
+
5
+ from port_ocean.context.metric_resource import metric_resource_context
6
+ from port_ocean.context.ocean import ocean
7
+ from port_ocean.helpers.metric.metric import MetricResourceKind, MetricType
8
+
9
+
10
+ def TimeMetric(phase: str) -> Any:
11
+ def decorator(func: Callable[..., Any]) -> Any:
12
+
13
+ @wraps(func)
14
+ async def wrapper(*args: Any, **kwargs: dict[Any, Any]) -> Any:
15
+ start = time.monotonic()
16
+ res = await func(*args, **kwargs)
17
+ end = time.monotonic()
18
+ duration = end - start
19
+ ocean.metrics.inc_metric(
20
+ name=MetricType.DURATION_NAME,
21
+ labels=[ocean.metrics.current_resource_kind(), phase],
22
+ value=duration,
23
+ )
24
+
25
+ return res
26
+
27
+ return wrapper
28
+
29
+ return decorator
30
+
31
+
32
+ def TimeMetricWithResourceKind(phase: str) -> Any:
33
+ def decorator(func: Callable[..., Any]) -> Any:
34
+
35
+ @wraps(func)
36
+ async def wrapper(*args: Any, **kwargs: dict[Any, Any]) -> Any:
37
+ async with metric_resource_context(MetricResourceKind.RECONCILIATION):
38
+ start = time.monotonic()
39
+ res = await func(*args, **kwargs)
40
+ end = time.monotonic()
41
+ duration = end - start
42
+ ocean.metrics.inc_metric(
43
+ name=MetricType.DURATION_NAME,
44
+ labels=[ocean.metrics.current_resource_kind(), phase],
45
+ value=duration,
46
+ )
47
+
48
+ return res
49
+
50
+ return wrapper
51
+
52
+ return decorator
@@ -154,7 +154,7 @@ async def test_sync_raw_mixin_self_dependency(
154
154
 
155
155
  # Add assertions for actual metrics
156
156
  metrics = mock_ocean.metrics.generate_metrics()
157
- assert len(metrics) == 2
157
+ assert len(metrics) == 3
158
158
 
159
159
  # Verify object counts
160
160
  for metric in metrics:
@@ -187,7 +187,7 @@ async def test_sync_raw_mixin_self_dependency(
187
187
  metric["metrics"]["phase"]["load"]["object_count_type"][
188
188
  "loaded"
189
189
  ]["object_count"]
190
- == 2
190
+ == 1
191
191
  )
192
192
 
193
193
  # Verify success
@@ -196,6 +196,14 @@ async def test_sync_raw_mixin_self_dependency(
196
196
  # Verify sync state
197
197
  assert metric["syncState"] == "completed"
198
198
 
199
+ if metric["kind"] == "reconciliation":
200
+ assert (
201
+ metric["metrics"]["phase"]["load"]["object_count_type"][
202
+ "failed"
203
+ ]["object_count"]
204
+ == 1
205
+ )
206
+
199
207
 
200
208
  @pytest.mark.asyncio
201
209
  async def test_sync_raw_mixin_circular_dependency(
@@ -282,7 +290,7 @@ async def test_sync_raw_mixin_circular_dependency(
282
290
 
283
291
  # Add assertions for actual metrics
284
292
  metrics = mock_ocean.metrics.generate_metrics()
285
- assert len(metrics) == 2
293
+ assert len(metrics) == 3
286
294
 
287
295
  # Verify object counts
288
296
  for metric in metrics:
@@ -315,7 +323,7 @@ async def test_sync_raw_mixin_circular_dependency(
315
323
  metric["metrics"]["phase"]["load"]["object_count_type"][
316
324
  "loaded"
317
325
  ]["object_count"]
318
- == 2
326
+ == 0
319
327
  )
320
328
 
321
329
  # Verify success
@@ -324,6 +332,14 @@ async def test_sync_raw_mixin_circular_dependency(
324
332
  # Verify sync state
325
333
  assert metric["syncState"] == "completed"
326
334
 
335
+ if metric["kind"] == "reconciliation":
336
+ assert (
337
+ metric["metrics"]["phase"]["load"]["object_count_type"][
338
+ "loaded"
339
+ ]["object_count"]
340
+ == 2
341
+ )
342
+
327
343
 
328
344
  @pytest.mark.asyncio
329
345
  async def test_sync_raw_mixin_dependency(
@@ -422,7 +438,7 @@ async def test_sync_raw_mixin_dependency(
422
438
 
423
439
  # Add assertions for actual metrics
424
440
  metrics = mock_ocean.metrics.generate_metrics()
425
- assert len(metrics) == 2
441
+ assert len(metrics) == 3
426
442
 
427
443
  # Verify object counts
428
444
  for metric in metrics:
@@ -458,6 +474,14 @@ async def test_sync_raw_mixin_dependency(
458
474
  # Verify sync state
459
475
  assert metric["syncState"] == "completed"
460
476
 
477
+ if metric["kind"] == "reconciliation":
478
+ assert (
479
+ metric["metrics"]["phase"]["load"]["object_count_type"][
480
+ "loaded"
481
+ ]["object_count"]
482
+ == 5
483
+ )
484
+
461
485
 
462
486
  @pytest.mark.asyncio
463
487
  async def test_register_raw(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.23.3"
3
+ version = "0.23.4"
4
4
  description = "Port Ocean is a CLI tool for managing your Port projects."
5
5
  readme = "README.md"
6
6
  homepage = "https://app.getport.io"
@@ -1,28 +0,0 @@
1
- from functools import wraps
2
- import time
3
- from typing import Any, Callable
4
-
5
- from port_ocean.context.ocean import ocean
6
- from port_ocean.helpers.metric.metric import MetricType
7
-
8
-
9
- def TimeMetric(phase: str) -> Any:
10
- def decorator(func: Callable[..., Any]) -> Any:
11
-
12
- @wraps(func)
13
- async def wrapper(*args: Any, **kwargs: dict[Any, Any]) -> Any:
14
- start = time.monotonic()
15
- res = await func(*args, **kwargs)
16
- end = time.monotonic()
17
- duration = end - start
18
- ocean.metrics.inc_metric(
19
- name=MetricType.DURATION_NAME,
20
- labels=[ocean.metrics.current_resource_kind(), phase],
21
- value=duration,
22
- )
23
-
24
- return res
25
-
26
- return wrapper
27
-
28
- return decorator
File without changes
File without changes