port-ocean 0.14.6__py3-none-any.whl → 0.15.0__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.

@@ -18,7 +18,7 @@ class TokenResponse(BaseModel):
18
18
 
19
19
  @property
20
20
  def expired(self) -> bool:
21
- return self._retrieved_time + self.expires_in < get_time()
21
+ return self._retrieved_time + self.expires_in <= get_time()
22
22
 
23
23
  @property
24
24
  def full_token(self) -> str:
@@ -48,6 +48,7 @@ class EntityClientMixin:
48
48
  ).lower(),
49
49
  "validation_only": str(validation_only).lower(),
50
50
  },
51
+ extensions={"retryable": True},
51
52
  )
52
53
 
53
54
  if response.is_error:
@@ -205,7 +206,6 @@ class EntityClientMixin:
205
206
  "include": ["blueprint", "identifier"],
206
207
  },
207
208
  extensions={"retryable": True},
208
- timeout=30,
209
209
  )
210
210
  handle_status_code(response)
211
211
  return [Entity.parse_obj(result) for result in response.json()["entities"]]
@@ -103,7 +103,7 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
103
103
 
104
104
  @validator("runtime")
105
105
  def validate_runtime(cls, runtime: Runtime) -> Runtime:
106
- if runtime == Runtime.Saas:
106
+ if runtime.is_saas_runtime:
107
107
  spec = get_spec_file()
108
108
  if spec is None:
109
109
  raise ValueError(
port_ocean/core/models.py CHANGED
@@ -8,8 +8,13 @@ from pydantic.fields import Field
8
8
 
9
9
  class Runtime(Enum):
10
10
  Saas = "Saas"
11
+ SaasOauth = "SaasOauth"
11
12
  OnPrem = "OnPrem"
12
13
 
14
+ @property
15
+ def is_saas_runtime(self) -> bool:
16
+ return self in [Runtime.Saas, Runtime.SaasOauth]
17
+
13
18
 
14
19
  class Entity(BaseModel):
15
20
  identifier: Any
@@ -134,7 +134,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
134
134
  """
135
135
  try:
136
136
  transport: httpx.BaseTransport = self._wrapped_transport # type: ignore
137
- if request.method in self._retryable_methods:
137
+ if self._is_retryable_method(request):
138
138
  send_method = partial(transport.handle_request)
139
139
  response = self._retry_operation(request, send_method)
140
140
  else:
port_ocean/ocean.py CHANGED
@@ -10,7 +10,6 @@ from pydantic import BaseModel
10
10
  from starlette.types import Scope, Receive, Send
11
11
 
12
12
  from port_ocean.core.handlers.resync_state_updater import ResyncStateUpdater
13
- from port_ocean.core.models import Runtime
14
13
  from port_ocean.clients.port.client import PortClient
15
14
  from port_ocean.config.settings import (
16
15
  IntegrationConfiguration,
@@ -73,7 +72,7 @@ class Ocean:
73
72
  self.app_initialized = False
74
73
 
75
74
  def is_saas(self) -> bool:
76
- return self.config.runtime == Runtime.Saas
75
+ return self.config.runtime.is_saas_runtime
77
76
 
78
77
  async def _setup_scheduled_resync(
79
78
  self,
@@ -0,0 +1,191 @@
1
+ import uvicorn
2
+ import os
3
+ from typing import Dict, Any
4
+ from fastapi import FastAPI, Request
5
+
6
+ SMOKE_TEST_SUFFIX = os.environ.get("SMOKE_TEST_SUFFIX", "smoke")
7
+
8
+ app = FastAPI()
9
+
10
+ FAKE_DEPARTMENT_BLUEPRINT = {
11
+ "identifier": f"fake-department-{SMOKE_TEST_SUFFIX}",
12
+ "title": "Fake Department",
13
+ "icon": "Blueprint",
14
+ "schema": {"properties": {"name": {"type": "string"}, "id": {"type": "string"}}},
15
+ "relations": {},
16
+ }
17
+ FAKE_PERSON_BLUEPRINT = {
18
+ "identifier": f"fake-person-{SMOKE_TEST_SUFFIX}",
19
+ "title": "Fake Person",
20
+ "icon": "Blueprint",
21
+ "schema": {
22
+ "properties": {
23
+ "status": {
24
+ "type": "string",
25
+ "enum": ["WORKING", "NOPE"],
26
+ "enumColors": {"WORKING": "green", "NOPE": "red"},
27
+ "title": "Status",
28
+ },
29
+ "email": {"type": "string", "format": "email", "title": "Email"},
30
+ "age": {"type": "number", "title": "Age"},
31
+ "bio": {"type": "string", "title": "Bio"},
32
+ }
33
+ },
34
+ "relations": {
35
+ "department": {
36
+ "title": "Department",
37
+ "description": "Fake Department",
38
+ "target": f"fake-department-{SMOKE_TEST_SUFFIX}",
39
+ "required": False,
40
+ "many": False,
41
+ }
42
+ },
43
+ }
44
+
45
+
46
+ @app.router.get("/v1/blueprints/{blueprint_id}")
47
+ @app.router.patch("/v1/blueprints/{blueprint_id}")
48
+ async def get_blueprint(blueprint_id: str) -> Dict[str, Any]:
49
+ return {
50
+ "blueprint": (
51
+ FAKE_PERSON_BLUEPRINT
52
+ if blueprint_id.startswith("fake-person")
53
+ else FAKE_DEPARTMENT_BLUEPRINT
54
+ )
55
+ }
56
+
57
+
58
+ @app.router.post("/v1/entities/search")
59
+ async def search_entities() -> Dict[str, Any]:
60
+ return {"ok": True, "entities": []}
61
+
62
+
63
+ @app.router.get("/v1/integration/{integration_id}")
64
+ @app.router.patch("/v1/integration/{integration_id}")
65
+ @app.router.patch("/v1/integration/{integration_id}/resync-state")
66
+ async def get_integration(integration_id: str) -> Dict[str, Any]:
67
+ return {
68
+ "integration": {
69
+ "identifer": integration_id,
70
+ "resyncState": {
71
+ "status": "completed",
72
+ "lastResyncEnd": "2024-11-20T12:01:54.225362+00:00",
73
+ "lastResyncStart": "2024-11-20T12:01:45.483844+00:00",
74
+ "nextResync": None,
75
+ "intervalInMinuets": None,
76
+ "updatedAt": "2024-11-20T12:01:54.355Z",
77
+ },
78
+ "config": {
79
+ "deleteDependentEntities": True,
80
+ "createMissingRelatedEntities": True,
81
+ "enableMergeEntity": True,
82
+ "resources": [
83
+ {
84
+ "kind": "fake-department",
85
+ "selector": {"query": "true"},
86
+ "port": {
87
+ "entity": {
88
+ "mappings": {
89
+ "identifier": ".id",
90
+ "title": ".name",
91
+ "blueprint": f'"fake-department-{SMOKE_TEST_SUFFIX}"',
92
+ "properties": {"name": ".name", "id": ".id"},
93
+ }
94
+ }
95
+ },
96
+ },
97
+ {
98
+ "kind": "fake-person",
99
+ "selector": {"query": "true"},
100
+ "port": {
101
+ "entity": {
102
+ "mappings": {
103
+ "identifier": ".id",
104
+ "title": ".name",
105
+ "blueprint": f'"fake-person-{SMOKE_TEST_SUFFIX}"',
106
+ "properties": {
107
+ "name": ".name",
108
+ "email": ".email",
109
+ "status": ".status",
110
+ "age": ".age",
111
+ "department": ".department.name",
112
+ },
113
+ "relations": {"department": ".department.id"},
114
+ }
115
+ }
116
+ },
117
+ },
118
+ ],
119
+ },
120
+ "installationType": "OnPrem",
121
+ "_orgId": "org_ZOMGMYUNIQUEID",
122
+ "_id": "integration_0dOOhnlJQDjMPnfe",
123
+ "identifier": f"smoke-test-integration-{SMOKE_TEST_SUFFIX}",
124
+ "integrationType": "smoke-test",
125
+ "createdBy": "APSQAYsYoIwPXqjn6XpwCAgnPakkNO67",
126
+ "updatedBy": "APSQAYsYoIwPXqjn6XpwCAgnPakkNO67",
127
+ "createdAt": "2024-11-20T12:01:42.651Z",
128
+ "updatedAt": "2024-11-20T12:01:54.355Z",
129
+ "clientId": "",
130
+ "logAttributes": {
131
+ "ingestId": "DOHSAIDHOMER",
132
+ "ingestUrl": "http://localhost:5555/logs/integration/DOHSAIDHOMER",
133
+ },
134
+ },
135
+ }
136
+
137
+
138
+ @app.router.post("/v1/blueprints/{blueprint_id}/entities")
139
+ async def upsert_entities(blueprint_id: str, request: Request) -> Dict[str, Any]:
140
+ json = await request.json()
141
+
142
+ return {
143
+ "ok": True,
144
+ "entity": json,
145
+ }
146
+
147
+
148
+ @app.router.post("/v1/auth/access_token")
149
+ async def auth_token() -> Dict[str, Any]:
150
+ return {
151
+ "accessToken": "ZOMG",
152
+ "expiresIn": 1232131231,
153
+ "tokenType": "adadad",
154
+ }
155
+
156
+
157
+ @app.router.delete("/v1/blueprints/{blueprint_id}/all-entities")
158
+ async def delete_blueprint(blueprint_id: str, request: Request) -> Dict[str, Any]:
159
+ return {"migrationId": "ZOMG"}
160
+
161
+
162
+ @app.router.get("/v1/migrations/{migration_id}")
163
+ async def migration(migration_id: str, request: Request) -> Dict[str, Any]:
164
+ return {
165
+ "migration": {
166
+ "id": migration_id,
167
+ "status": "COMPLETE",
168
+ "actor": "Dwayne Scissors Johnson",
169
+ "sourceBlueprint": "leBlue",
170
+ "mapping": {},
171
+ }
172
+ }
173
+
174
+
175
+ CATCH_ALL = "/{full_path:path}"
176
+
177
+
178
+ @app.router.get(CATCH_ALL)
179
+ @app.router.post(CATCH_ALL)
180
+ @app.router.patch(CATCH_ALL)
181
+ @app.router.delete(CATCH_ALL)
182
+ async def catch_all(full_path: str, request: Request) -> str:
183
+ return f"Hello there from fake Port API - {full_path}, thanks for accessing me with {request.method}"
184
+
185
+
186
+ def start() -> None:
187
+ uvicorn.run(app, host="0.0.0.0", port=5555)
188
+
189
+
190
+ if __name__ == "__main__":
191
+ start()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.14.6
3
+ Version: 0.15.0
4
4
  Summary: Port Ocean is a CLI tool for managing your Port projects.
5
5
  Home-page: https://app.getport.io
6
6
  Keywords: ocean,port-ocean,port
@@ -45,11 +45,11 @@ port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.
45
45
  port_ocean/cli/utils.py,sha256=IUK2UbWqjci-lrcDdynZXqVP5B5TcjF0w5CpEVUks-k,54
46
46
  port_ocean/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  port_ocean/clients/port/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- port_ocean/clients/port/authentication.py,sha256=BEcSosMi8B2pD70yFaunQvxYWRJZ030PFbHEs_MAGw0,3446
48
+ port_ocean/clients/port/authentication.py,sha256=6-uDMWsJ0xLe1-9IoYXHWmwtufj8rJR4BCRXJlSkCSQ,3447
49
49
  port_ocean/clients/port/client.py,sha256=Xd8Jk25Uh4WXY_WW-z1Qbv6F3ZTBFPoOolsxHMfozKw,3366
50
50
  port_ocean/clients/port/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  port_ocean/clients/port/mixins/blueprints.py,sha256=POBl4uDocrgJBw4rvCAzwRcD4jk-uBL6pDAuKMTajdg,4633
52
- port_ocean/clients/port/mixins/entities.py,sha256=WdqT1gyS81pByUl9xIfZz_xEHRaBfDuZ-ekKX53oBSE,8870
52
+ port_ocean/clients/port/mixins/entities.py,sha256=CnSU3dw1RTZUWYBTLP3KP7CyMweNcoDi1OlSWBwjXWU,8894
53
53
  port_ocean/clients/port/mixins/integrations.py,sha256=t8OSa7Iopnpp8IOEcp3a7WgwOcJEBdFow9UbGDKWxKI,4858
54
54
  port_ocean/clients/port/mixins/migrations.py,sha256=A6896oJF6WbFL2WroyTkMzr12yhVyWqGoq9dtLNSKBY,1457
55
55
  port_ocean/clients/port/retry_transport.py,sha256=PtIZOAZ6V-ncpVysRUsPOgt8Sf01QLnTKB5YeKBxkJk,1861
@@ -58,7 +58,7 @@ port_ocean/clients/port/utils.py,sha256=SjhgmJXAqH2JqXfGy8GoGwzUYiJvUhWDrJyxQcen
58
58
  port_ocean/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
59
  port_ocean/config/base.py,sha256=x1gFbzujrxn7EJudRT81C6eN9WsYAb3vOHwcpcpX8Tc,6370
60
60
  port_ocean/config/dynamic.py,sha256=qOFkRoJsn_BW7581omi_AoMxoHqasf_foxDQ_G11_SI,2030
61
- port_ocean/config/settings.py,sha256=65LATPdQ4YBdUTgQHMtZvzzPVrOxWUqAP7eerwFGZvg,4333
61
+ port_ocean/config/settings.py,sha256=cxGnOTO9cEwwFcTSzOmwMw1yPkQHniVJFyCQCyEZ6yY,4333
62
62
  port_ocean/consumers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  port_ocean/consumers/kafka_consumer.py,sha256=N8KocjBi9aR0BOPG8hgKovg-ns_ggpEjrSxqSqF_BSo,4710
64
64
  port_ocean/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -102,7 +102,7 @@ port_ocean/core/integrations/mixins/handler.py,sha256=mZ7-0UlG3LcrwJttFbMe-R4xcO
102
102
  port_ocean/core/integrations/mixins/sync.py,sha256=B9fEs8faaYLLikH9GBjE_E61vo0bQDjIGQsQ1SRXOlA,3931
103
103
  port_ocean/core/integrations/mixins/sync_raw.py,sha256=BGS5EnZ2N3ifcAi94Wo-ZassSJ-_Se9eFJMpBDT7pNY,18841
104
104
  port_ocean/core/integrations/mixins/utils.py,sha256=7y1rGETZIjOQadyIjFJXIHKkQFKx_SwiP-TrAIsyyLY,2303
105
- port_ocean/core/models.py,sha256=dJ2_olTdbjUpObQJNmg7e7EENU_zZiX6XOaknNp54B0,1342
105
+ port_ocean/core/models.py,sha256=5jnXFkSpS9BfvOy0KLWWvg96I3aXjMHmfQ_4lCBdz_k,1481
106
106
  port_ocean/core/ocean_types.py,sha256=3_d8-n626f1kWLQ_Jxw194LEyrOVupz05qs_Y1pvB-A,990
107
107
  port_ocean/core/utils.py,sha256=40UjRauRJO47WDSNn9bkCRD2bfhfB3e-dnOLULnuVzE,3631
108
108
  port_ocean/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -115,13 +115,13 @@ port_ocean/exceptions/port_defaults.py,sha256=45Bno5JEB-GXztvKsy8mw7TrydQmw13-4J
115
115
  port_ocean/exceptions/utils.py,sha256=gjOqpi-HpY1l4WlMFsGA9yzhxDhajhoGGdDDyGbLnqI,197
116
116
  port_ocean/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
117
117
  port_ocean/helpers/async_client.py,sha256=SRlP6o7_FCSY3UHnRlZdezppePVxxOzZ0z861vE3K40,1783
118
- port_ocean/helpers/retry.py,sha256=WO4yDFUd9NexZ0kESqxeTxBxNabU7_utKzgTj2-kMaM,15632
118
+ port_ocean/helpers/retry.py,sha256=fmvaUFLIW6PICgYH4RI5rrKBXDxCAhR1Gtl0dsb2kMs,15625
119
119
  port_ocean/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
120
  port_ocean/log/handlers.py,sha256=ncVjgqrZRh6BhyRrA6DQG86Wsbxph1yWYuEC0cWfe-Q,3631
121
121
  port_ocean/log/logger_setup.py,sha256=CoEDowe5OwNOL_5clU6Z4faktfh0VWaOTS0VLmyhHjw,2404
122
122
  port_ocean/log/sensetive.py,sha256=lVKiZH6b7TkrZAMmhEJRhcl67HNM94e56x12DwFgCQk,2920
123
123
  port_ocean/middlewares.py,sha256=9wYCdyzRZGK1vjEJ28FY_DkfwDNENmXp504UKPf5NaQ,2727
124
- port_ocean/ocean.py,sha256=NVdvooP0AiGyVs38VE8xXj6bzeT3XLoIPnh5FAS5ouM,5290
124
+ port_ocean/ocean.py,sha256=XxO-aRExs1hcy6aJY_nceu-QXRWB2ZLpkIPPuBkp-bQ,5247
125
125
  port_ocean/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
126
126
  port_ocean/run.py,sha256=rTxBlrQd4yyrtgErCFJCHCEHs7d1OXrRiJehUYmIbN0,2212
127
127
  port_ocean/sonar-project.properties,sha256=X_wLzDOkEVmpGLRMb2fg9Rb0DxWwUFSvESId8qpvrPI,73
@@ -131,6 +131,7 @@ port_ocean/tests/conftest.py,sha256=JXASSS0IY0nnR6bxBflhzxS25kf4iNaABmThyZ0mZt8,
131
131
  port_ocean/tests/core/defaults/test_common.py,sha256=sR7RqB3ZYV6Xn6NIg-c8k5K6JcGsYZ2SCe_PYX5vLYM,5560
132
132
  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=Yv03P-LDcJCKZ21exiTFrcT1eu0zn6Z954dilxrb52Y,10842
133
133
  port_ocean/tests/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
134
+ port_ocean/tests/helpers/fake_port_api.py,sha256=9rtjC6iTQMfzWK6WipkDzzG0b1IIaRmvdJLOyV613vE,6479
134
135
  port_ocean/tests/helpers/fixtures.py,sha256=IQEplbHhRgjrAsZlnXrgSYA5YQEn25I9HgO3_Fjibxg,1481
135
136
  port_ocean/tests/helpers/integration.py,sha256=_RxS-RHpu11lrbhUXYPZp862HLWx8AoD7iZM6iXN8rs,1104
136
137
  port_ocean/tests/helpers/ocean_app.py,sha256=8BysIhNqtTwhjnya5rr0AtrjulfJnJJMFz5cPUxIpLk,2167
@@ -150,8 +151,8 @@ port_ocean/utils/repeat.py,sha256=0EFWM9d8lLXAhZmAyczY20LAnijw6UbIECf5lpGbOas,32
150
151
  port_ocean/utils/signal.py,sha256=K-6kKFQTltcmKDhtyZAcn0IMa3sUpOHGOAUdWKgx0_E,1369
151
152
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
152
153
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
153
- port_ocean-0.14.6.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
154
- port_ocean-0.14.6.dist-info/METADATA,sha256=KTjM9cT2YRaEy1XsgkKN8uAlzVfCE9pxm4KGMTVvzN0,6673
155
- port_ocean-0.14.6.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
156
- port_ocean-0.14.6.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
157
- port_ocean-0.14.6.dist-info/RECORD,,
154
+ port_ocean-0.15.0.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
155
+ port_ocean-0.15.0.dist-info/METADATA,sha256=GLoKGQDzcULrCpX8Q_2lFrExJPbl7qD8RclNc3zWNds,6673
156
+ port_ocean-0.15.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
157
+ port_ocean-0.15.0.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
158
+ port_ocean-0.15.0.dist-info/RECORD,,