port-ocean 0.12.2.dev17__py3-none-any.whl → 0.12.2.dev20__py3-none-any.whl

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

Potentially problematic release.


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

@@ -1,6 +1,5 @@
1
1
  from typing import Callable, TYPE_CHECKING, Any, Literal, Union
2
2
 
3
- from fastapi import APIRouter
4
3
  from pydantic.main import BaseModel
5
4
  from werkzeug.local import LocalProxy
6
5
 
@@ -44,10 +43,6 @@ class PortOceanContext:
44
43
  def config(self) -> "IntegrationConfiguration":
45
44
  return self.app.config
46
45
 
47
- @property
48
- def router(self) -> APIRouter:
49
- return self.app.integration_router
50
-
51
46
  @property
52
47
  def integration(self) -> "BaseIntegration":
53
48
  return self.app.integration
@@ -1,7 +1,7 @@
1
1
  import abc
2
2
 
3
- from fastapi.responses import Response, PlainTextResponse
4
3
  from port_ocean.exceptions.base import BaseOceanException
4
+ from starlette.responses import Response, PlainTextResponse
5
5
 
6
6
 
7
7
  class BaseAPIException(BaseOceanException, abc.ABC):
port_ocean/middlewares.py CHANGED
@@ -1,73 +1,70 @@
1
- from typing import Callable, Awaitable
2
-
3
- from fastapi import Request, Response
4
1
  from loguru import logger
2
+ from starlette.requests import Request
3
+ from starlette.responses import Response
5
4
 
6
5
  from port_ocean.exceptions.api import BaseAPIException, InternalServerException
7
6
  from .context.event import event_context, EventType
8
7
  from .context.ocean import ocean
9
8
  from .utils.misc import get_time, generate_uuid
9
+ from starlette.middleware.base import (
10
+ BaseHTTPMiddleware,
11
+ RequestResponseEndpoint,
12
+ )
10
13
 
11
14
 
12
- async def _handle_silently(
13
- call_next: Callable[[Request], Awaitable[Response]], request: Request
14
- ) -> Response:
15
- response: Response
16
- try:
17
- if request.url.path.startswith("/integration"):
18
- async with event_context(EventType.HTTP_REQUEST, trigger_type="request"):
19
- await ocean.integration.port_app_config_handler.get_port_app_config()
20
- response = await call_next(request)
21
- else:
22
- response = await call_next(request)
15
+ class RequestHandlerMiddleware(BaseHTTPMiddleware):
16
+ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
17
+ start_time = get_time(seconds_precision=False)
18
+ request_id = generate_uuid()
23
19
 
24
- except BaseAPIException as ex:
25
- response = ex.response()
26
- if response.status_code < 500:
27
- logger.bind(exception=str(ex)).info(
28
- "Request did not succeed due to client-side error"
20
+ with logger.contextualize(request_id=request_id):
21
+ log_level = (
22
+ "DEBUG"
23
+ if request.url.path == "/docs" or request.url.path == "/openapi.json"
24
+ else "INFO"
29
25
  )
30
- else:
31
- logger.opt(exception=True).warning(
32
- "Request did not succeed due to server-side error"
26
+ logger.bind(url=str(request.url), method=request.method).log(
27
+ log_level, f"Request to {request.url.path} started"
33
28
  )
29
+ response = await self._handle_silently(request, call_next)
34
30
 
35
- except Exception:
36
- logger.opt(exception=True).error("Request failed due to unexpected error")
37
- response = InternalServerException().response()
38
-
39
- return response
31
+ end_time = get_time(seconds_precision=False)
32
+ time_elapsed = round(end_time - start_time, 5)
33
+ response.headers["X-Request-ID"] = request_id
34
+ response.headers["X-Process-Time"] = str(time_elapsed)
35
+ logger.bind(
36
+ time_elapsed=time_elapsed, response_status=response.status_code
37
+ ).log(log_level, f"Request to {request.url.path} ended")
40
38
 
39
+ return response
41
40
 
42
- async def request_handler(
43
- request: Request, call_next: Callable[[Request], Awaitable[Response]]
44
- ) -> Response:
45
- """Middleware used by FastAPI to process each request, featuring:
46
-
47
- - Contextualize request logs with a unique Request ID (UUID4) for each unique request.
48
- - Catch exceptions during the request handling. Translate custom API exceptions into responses,
49
- or treat (and log) unexpected exceptions.
50
- """
51
- start_time = get_time(seconds_precision=False)
52
- request_id = generate_uuid()
41
+ async def _handle_silently(
42
+ self, request: Request, call_next: RequestResponseEndpoint
43
+ ) -> Response:
44
+ response: Response
45
+ try:
46
+ if request.url.path.startswith("/integration"):
47
+ async with event_context(
48
+ EventType.HTTP_REQUEST, trigger_type="request"
49
+ ):
50
+ await ocean.integration.port_app_config_handler.get_port_app_config()
51
+ response = await call_next(request)
52
+ else:
53
+ response = await call_next(request)
53
54
 
54
- with logger.contextualize(request_id=request_id):
55
- log_level = (
56
- "DEBUG"
57
- if request.url.path == "/docs" or request.url.path == "/openapi.json"
58
- else "INFO"
59
- )
60
- logger.bind(url=str(request.url), method=request.method).log(
61
- log_level, f"Request to {request.url.path} started"
62
- )
63
- response = await _handle_silently(call_next, request)
55
+ except BaseAPIException as ex:
56
+ response = ex.response()
57
+ if response.status_code < 500:
58
+ logger.bind(exception=str(ex)).info(
59
+ "Request did not succeed due to client-side error"
60
+ )
61
+ else:
62
+ logger.opt(exception=True).warning(
63
+ "Request did not succeed due to server-side error"
64
+ )
64
65
 
65
- end_time = get_time(seconds_precision=False)
66
- time_elapsed = round(end_time - start_time, 5)
67
- response.headers["X-Request-ID"] = request_id
68
- response.headers["X-Process-Time"] = str(time_elapsed)
69
- logger.bind(
70
- time_elapsed=time_elapsed, response_status=response.status_code
71
- ).log(log_level, f"Request to {request.url.path} ended")
66
+ except Exception:
67
+ logger.opt(exception=True).error("Request failed due to unexpected error")
68
+ response = InternalServerException().response()
72
69
 
73
70
  return response
port_ocean/ocean.py CHANGED
@@ -1,12 +1,13 @@
1
1
  import asyncio
2
2
  import sys
3
3
  import threading
4
- from contextlib import asynccontextmanager
5
- from typing import Callable, Any, Dict, AsyncIterator, Type
4
+ from typing import Callable, Any, Dict, Type
6
5
 
7
- from fastapi import FastAPI, APIRouter
8
6
  from loguru import logger
9
7
  from pydantic import BaseModel
8
+ from starlette.middleware import Middleware
9
+ from starlette.responses import JSONResponse
10
+ from starlette.routing import Route
10
11
  from starlette.types import Scope, Receive, Send
11
12
 
12
13
  from port_ocean.clients.port.client import PortClient
@@ -18,25 +19,50 @@ from port_ocean.context.ocean import (
18
19
  ocean,
19
20
  initialize_port_ocean_context,
20
21
  )
22
+ from port_ocean.core.handlers.resync_state_updater import ResyncStateUpdater
21
23
  from port_ocean.core.integrations.base import BaseIntegration
22
24
  from port_ocean.core.models import Runtime
25
+ from port_ocean.log.sensetive import sensitive_log_filter
26
+ from port_ocean.middlewares import RequestHandlerMiddleware
23
27
  from port_ocean.utils.repeat import repeat_every
24
28
  from port_ocean.utils.signal import signal_handler
25
29
  from port_ocean.version import __integration_version__
30
+ import contextlib
31
+
32
+ from starlette.applications import Starlette
26
33
 
27
34
 
28
35
  class Ocean:
29
36
  def __init__(
30
37
  self,
31
- app: FastAPI | None = None,
38
+ app: Starlette | None = None,
32
39
  integration_class: Callable[[PortOceanContext], BaseIntegration] | None = None,
33
- integration_router: APIRouter | None = None,
40
+ integration_router: None = None,
34
41
  config_factory: Type[BaseModel] | None = None,
35
42
  config_override: Dict[str, Any] | None = None,
36
43
  ):
37
44
  initialize_port_ocean_context(self)
38
- self.fast_api_app = app or FastAPI()
39
- # self.fast_api_app.middleware("http")(request_handler)
45
+
46
+ @contextlib.asynccontextmanager
47
+ async def lifespan(app):
48
+ try:
49
+ await self.integration.start()
50
+ await self._setup_scheduled_resync()
51
+ yield None
52
+ except Exception:
53
+ logger.exception("Integration had a fatal error. Shutting down.")
54
+ sys.exit("Server stopped")
55
+ finally:
56
+ signal_handler.exit()
57
+
58
+ async def handle_webhook_request(data: dict[str, Any]) -> dict[str, Any]:
59
+ return JSONResponse({"ok": True})
60
+
61
+ self.starlette_app = Starlette(
62
+ routes=[Route("/integration/webhook", endpoint=handle_webhook_request)],
63
+ middleware=[Middleware(RequestHandlerMiddleware)],
64
+ lifespan=lifespan,
65
+ )
40
66
 
41
67
  self.config = IntegrationConfiguration(
42
68
  # type: ignore
@@ -45,10 +71,9 @@ class Ocean:
45
71
  )
46
72
 
47
73
  # add the integration sensitive configuration to the sensitive patterns to mask out
48
- # sensitive_log_filter.hide_sensitive_strings(
49
- # *self.config.get_sensitive_fields_data()
50
- # )
51
- # self.integration_router = integration_router or APIRouter()
74
+ sensitive_log_filter.hide_sensitive_strings(
75
+ *self.config.get_sensitive_fields_data()
76
+ )
52
77
 
53
78
  self.port_client = PortClient(
54
79
  base_url=self.config.port.base_url,
@@ -62,9 +87,9 @@ class Ocean:
62
87
  integration_class(ocean) if integration_class else BaseIntegration(ocean)
63
88
  )
64
89
 
65
- # self.resync_state_updater = ResyncStateUpdater(
66
- # self.port_client, self.config.scheduled_resync_interval
67
- # )
90
+ self.resync_state_updater = ResyncStateUpdater(
91
+ self.port_client, self.config.scheduled_resync_interval
92
+ )
68
93
 
69
94
  def is_saas(self) -> bool:
70
95
  return self.config.runtime == Runtime.Saas
@@ -109,19 +134,4 @@ class Ocean:
109
134
  await repeated_function()
110
135
 
111
136
  async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
112
- # self.fast_api_app.include_router(self.integration_router, prefix="/integration")
113
-
114
- @asynccontextmanager
115
- async def lifecycle(_: FastAPI) -> AsyncIterator[None]:
116
- try:
117
- await self.integration.start()
118
- await self._setup_scheduled_resync()
119
- yield None
120
- except Exception:
121
- logger.exception("Integration had a fatal error. Shutting down.")
122
- sys.exit("Server stopped")
123
- finally:
124
- signal_handler.exit()
125
-
126
- self.fast_api_app.router.lifespan_context = lifecycle
127
- await self.fast_api_app(scope, receive, send)
137
+ await self.starlette_app(scope, receive, send)
port_ocean/run.py CHANGED
@@ -7,8 +7,8 @@ from pydantic import BaseModel
7
7
 
8
8
  from port_ocean.bootstrap import create_default_app
9
9
  from port_ocean.config.dynamic import default_config_factory
10
- from port_ocean.config.settings import LogLevelType, ApplicationSettings
11
- from port_ocean.core.defaults import initialize_defaults
10
+ from port_ocean.config.settings import ApplicationSettings, LogLevelType
11
+ from port_ocean.core.defaults.initialize import initialize_defaults
12
12
  from port_ocean.core.utils import validate_integration_runtime
13
13
  from port_ocean.log.logger_setup import setup_logger
14
14
  from port_ocean.ocean import Ocean
@@ -60,4 +60,4 @@ def run(
60
60
 
61
61
  initialize_defaults(app.integration.AppConfigHandlerClass.CONFIG_CLASS, app.config)
62
62
 
63
- uvicorn.run(app, host="0.0.0.0", port=8000, loop="none")
63
+ uvicorn.run(app, host="0.0.0.0", port=application_settings.port)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.12.2.dev17
3
+ Version: 0.12.2.dev20
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
@@ -26,7 +26,7 @@ Requires-Dist: aiostream (>=0.5.2,<0.7.0)
26
26
  Requires-Dist: click (>=8.1.3,<9.0.0) ; extra == "cli"
27
27
  Requires-Dist: confluent-kafka (>=2.1.1,<3.0.0)
28
28
  Requires-Dist: cookiecutter (>=2.1.1,<3.0.0) ; extra == "cli"
29
- Requires-Dist: fastapi (>=0.100,<0.112)
29
+ Requires-Dist: fastapi (>=0.100,<0.116)
30
30
  Requires-Dist: httpx (>=0.24.1,<0.28.0)
31
31
  Requires-Dist: jinja2-time (>=0.2.0,<0.3.0) ; extra == "cli"
32
32
  Requires-Dist: jq (>=1.8.0,<2.0.0)
@@ -40,7 +40,7 @@ Requires-Dist: rich (>=13.4.1,<14.0.0) ; extra == "cli"
40
40
  Requires-Dist: six (>=1.16.0,<2.0.0)
41
41
  Requires-Dist: tomli (>=2.0.1,<3.0.0)
42
42
  Requires-Dist: urllib3 (>=1.26.16,<3.0.0)
43
- Requires-Dist: uvicorn (>=0.22,<0.31)
43
+ Requires-Dist: uvicorn (>=0.22,<0.33)
44
44
  Requires-Dist: werkzeug (>=2.3.4,<4.0.0)
45
45
  Project-URL: Repository, https://github.com/port-labs/Port-Ocean
46
46
  Description-Content-Type: text/markdown
@@ -57,7 +57,7 @@ port_ocean/consumers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
57
57
  port_ocean/consumers/kafka_consumer.py,sha256=N8KocjBi9aR0BOPG8hgKovg-ns_ggpEjrSxqSqF_BSo,4710
58
58
  port_ocean/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
59
  port_ocean/context/event.py,sha256=WduGbCPgm2J2a63EY4J3XWwFGSt3ja1acBVpyI_ciMo,5430
60
- port_ocean/context/ocean.py,sha256=2EreWOj-N2H7QUjEt5wGiv5KHP4pTZc70tn_wHcpF4w,4657
60
+ port_ocean/context/ocean.py,sha256=0NQj6nPCAYAKvYgb00zRDz88_7BDUR04-dFsA2XBXQE,4534
61
61
  port_ocean/context/resource.py,sha256=yDj63URzQelj8zJPh4BAzTtPhpKr9Gw9DRn7I_0mJ1s,1692
62
62
  port_ocean/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  port_ocean/core/defaults/__init__.py,sha256=8qCZg8n06WAdMu9s_FiRtDYLGPGHbOuS60vapeUoAks,142
@@ -100,7 +100,7 @@ port_ocean/core/models.py,sha256=dJ2_olTdbjUpObQJNmg7e7EENU_zZiX6XOaknNp54B0,134
100
100
  port_ocean/core/ocean_types.py,sha256=3_d8-n626f1kWLQ_Jxw194LEyrOVupz05qs_Y1pvB-A,990
101
101
  port_ocean/core/utils.py,sha256=40UjRauRJO47WDSNn9bkCRD2bfhfB3e-dnOLULnuVzE,3631
102
102
  port_ocean/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
- port_ocean/exceptions/api.py,sha256=TLmTMqn4uHGaHgZK8PMIJ0TVJlPB4iP7xl9rx7GtCyY,426
103
+ port_ocean/exceptions/api.py,sha256=gb2jqBfRv21-Y5BQ8-1DmYMT7uv7QEhhNDvpZCvqdKU,428
104
104
  port_ocean/exceptions/base.py,sha256=uY4DX7fIITDFfemCJDWpaZi3bD51lcANc5swpoNvMJA,46
105
105
  port_ocean/exceptions/clients.py,sha256=LKLLs-Zy3caNG85rwxfOw2rMr8qqVV6SHUq4fRCZ99U,180
106
106
  port_ocean/exceptions/context.py,sha256=mA8HII6Rl4QxKUz98ppy1zX3kaziaen21h1ZWuU3ADc,372
@@ -114,10 +114,10 @@ port_ocean/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
114
  port_ocean/log/handlers.py,sha256=k9G_Mb4ga2-Jke9irpdlYqj6EYiwv0gEsh4TgyqqOmI,2853
115
115
  port_ocean/log/logger_setup.py,sha256=qSeVwnivV4WoLx_4SfBwn2PtmUpNdkSEgfm0C8B3yUw,2332
116
116
  port_ocean/log/sensetive.py,sha256=lVKiZH6b7TkrZAMmhEJRhcl67HNM94e56x12DwFgCQk,2920
117
- port_ocean/middlewares.py,sha256=9wYCdyzRZGK1vjEJ28FY_DkfwDNENmXp504UKPf5NaQ,2727
118
- port_ocean/ocean.py,sha256=7NV-QVP-NivyZNoJXp2Mz6NGjkR0ngqml2zfdV5Qulc,4861
117
+ port_ocean/middlewares.py,sha256=K_FGt39YgiC0397W3ON1Z0n0bRIke95sZkw7a0xOiII,2737
118
+ port_ocean/ocean.py,sha256=MKz9K83a9zUrazBkV4jVJDxJnIynomLfwZ0L39IR-hc,5133
119
119
  port_ocean/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
- port_ocean/run.py,sha256=6FHXSLkb7Lkyf15iQH7tifo-z2Z1RolkNaNju9rWFoM,2193
120
+ port_ocean/run.py,sha256=rTxBlrQd4yyrtgErCFJCHCEHs7d1OXrRiJehUYmIbN0,2212
121
121
  port_ocean/sonar-project.properties,sha256=X_wLzDOkEVmpGLRMb2fg9Rb0DxWwUFSvESId8qpvrPI,73
122
122
  port_ocean/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
123
  port_ocean/tests/clients/port/mixins/test_entities.py,sha256=A9myrnkLhKSQrnOLv1Zz2wiOVSxW65Q9RIUIRbn_V7w,1586
@@ -140,8 +140,8 @@ port_ocean/utils/repeat.py,sha256=0EFWM9d8lLXAhZmAyczY20LAnijw6UbIECf5lpGbOas,32
140
140
  port_ocean/utils/signal.py,sha256=K-6kKFQTltcmKDhtyZAcn0IMa3sUpOHGOAUdWKgx0_E,1369
141
141
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
142
142
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
143
- port_ocean-0.12.2.dev17.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
144
- port_ocean-0.12.2.dev17.dist-info/METADATA,sha256=r6PD39j-z-I0Fb1a_bEg6t7cueWWA1hs8As9lACIufk,6671
145
- port_ocean-0.12.2.dev17.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
146
- port_ocean-0.12.2.dev17.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
147
- port_ocean-0.12.2.dev17.dist-info/RECORD,,
143
+ port_ocean-0.12.2.dev20.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
144
+ port_ocean-0.12.2.dev20.dist-info/METADATA,sha256=3mb_wnpmLv0NDDR_QREkEu6ZRpKP6nuW3dk0ciH1LyE,6671
145
+ port_ocean-0.12.2.dev20.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
146
+ port_ocean-0.12.2.dev20.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
147
+ port_ocean-0.12.2.dev20.dist-info/RECORD,,