polyapi-python 0.3.1.dev0__py3-none-any.whl → 0.3.1.dev2__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.
polyapi/sync.py ADDED
@@ -0,0 +1,122 @@
1
+ import os
2
+ from datetime import datetime
3
+ from typing import List, Dict
4
+ import requests
5
+
6
+ from polyapi.deployables import (
7
+ prepare_deployable_directory, load_deployable_records,
8
+ save_deployable_records, remove_deployable_records,
9
+ get_cache_deployments_revision, write_updated_deployable,
10
+ DeployableRecord, SyncDeployment, Deployment
11
+ )
12
+
13
+ DEPLOY_ORDER = [
14
+ 'server-function',
15
+ 'client-function',
16
+ ]
17
+
18
+ def read_file(file_path: str) -> str:
19
+ with open(file_path, 'r', encoding='utf-8') as file:
20
+ return file.read()
21
+
22
+ def group_by(items: List[Dict], key: str) -> Dict[str, List[Dict]]:
23
+ grouped = {}
24
+ for item in items:
25
+ grouped.setdefault(item[key], []).append(item)
26
+ return grouped
27
+
28
+ def remove_deployable(deployable: SyncDeployment) -> bool:
29
+ # Example function call, adjust as needed
30
+ url = f"{deployable['instance']}/{deployable['type']}/{deployable['name']}"
31
+ response = requests.get(url)
32
+ if response.status_code != 200:
33
+ return False
34
+ requests.delete(url)
35
+ return True
36
+
37
+ def sync_deployable_and_get_id(deployable: SyncDeployment, code: str) -> str:
38
+ # Example function call, adjust as needed
39
+ url = f"{deployable['instance']}/{deployable['type']}"
40
+ print(deployable)
41
+ payload = {
42
+ "context": deployable["context"],
43
+ "name": deployable["name"],
44
+ "description": deployable["description"],
45
+ "code": code,
46
+ "typeSchemas": deployable["typeSchemas"],
47
+ "config": deployable["config"]
48
+ }
49
+ response = requests.post(url, json=payload)
50
+ response.raise_for_status()
51
+ return response.json()['id']
52
+
53
+ def sync_deployable(deployable: SyncDeployment) -> Deployment:
54
+ code = read_file(deployable['file'])
55
+ id = sync_deployable_and_get_id(deployable, code)
56
+ return {
57
+ "name": deployable["name"],
58
+ "context": deployable["context"],
59
+ "instance": deployable["instance"],
60
+ "type": deployable["type"],
61
+ "id": id,
62
+ "deployed": datetime.now().isoformat(),
63
+ "fileRevision": deployable["fileRevision"],
64
+ }
65
+
66
+ def sync_deployables(dry_run: bool, instance: str = os.getenv('POLY_API_BASE_URL')):
67
+ prepare_deployable_directory()
68
+ git_revision = get_cache_deployments_revision()
69
+ all_deployables = load_deployable_records()
70
+ to_remove: List[DeployableRecord] = []
71
+
72
+ if not all_deployables:
73
+ print('No deployables found. Skipping sync.')
74
+ return
75
+
76
+ # TODO: Improve our deploy ordering.
77
+ # Right now we're doing rudimentary ordering by type
78
+ # But this does not safely handle cases where one server function may reference another
79
+ # We should parse the functions bodies for references to other Poly deployables and work them into a DAG
80
+ grouped_deployables = group_by(all_deployables, 'type')
81
+ for type_name in DEPLOY_ORDER:
82
+ deployables = grouped_deployables.get(type_name, [])
83
+ for deployable in deployables:
84
+ previous_deployment = next((d for d in deployable.get('deployments', []) if d['instance'] == instance), None)
85
+ git_revision_changed = git_revision != deployable['gitRevision']
86
+ file_revision_changed = not previous_deployment or previous_deployment['fileRevision'] != deployable['fileRevision']
87
+
88
+ action = 'REMOVED' if git_revision_changed else \
89
+ 'ADDED' if not previous_deployment else \
90
+ 'UPDATED' if file_revision_changed else 'OK'
91
+
92
+ if not dry_run and (git_revision_changed or file_revision_changed):
93
+ # Any deployable may be deployed to multiple instances/environments at the same time
94
+ # So we reduce the deployable record down to a single instance we want to deploy to
95
+ if previous_deployment:
96
+ sync_deployment = { **deployable, **previous_deployment, "instance": instance }
97
+ else:
98
+ sync_deployment = { **deployable, "instance": instance }
99
+ if git_revision == deployable['gitRevision']:
100
+ deployment = sync_deployable(sync_deployment)
101
+ print(deployment)
102
+ if previous_deployment:
103
+ previous_deployment.update(deployment)
104
+ else:
105
+ deployable['deployments'].insert(0, deployment)
106
+ else:
107
+ found = remove_deployable(sync_deployment)
108
+ action = 'NOT FOUND' if not found else action
109
+ remove_index = all_deployables.index(deployable)
110
+ to_remove.append(all_deployables.pop(remove_index))
111
+
112
+ print(f"{'Would sync' if dry_run else 'Synced'} {deployable['type'].replace('-', ' ')} {deployable['context']}.{deployable['name']}: {'TO BE ' if dry_run else ''}{action}")
113
+
114
+ if dry_run:
115
+ return
116
+
117
+ for deployable in all_deployables:
118
+ write_updated_deployable(deployable, True)
119
+
120
+ save_deployable_records(all_deployables)
121
+ if to_remove:
122
+ remove_deployable_records(to_remove)
polyapi/typedefs.py CHANGED
@@ -1,5 +1,5 @@
1
- from typing import Any, List, Literal, Dict, TypedDict
2
- from typing_extensions import NotRequired
1
+ from typing import Any, List, Literal, Dict, Union, Optional
2
+ from typing_extensions import NotRequired, TypedDict
3
3
 
4
4
 
5
5
  class PropertySpecification(TypedDict):
@@ -53,4 +53,22 @@ class VariableSpecDto(TypedDict):
53
53
  name: str
54
54
  description: str
55
55
  variable: VariableSpecification
56
- type: Literal['serverVariable']
56
+ type: Literal['serverVariable']
57
+
58
+ Visibility = Union[Literal['PUBLIC'], Literal['TENANT'], Literal['ENVIRONMENT']]
59
+
60
+
61
+ class PolyDeployable(TypedDict, total=False):
62
+ context: str
63
+ name: str
64
+ disable_ai: Optional[bool] # Optional field to disable AI
65
+
66
+
67
+ class PolyServerFunction(PolyDeployable):
68
+ logs_enabled: Optional[bool]
69
+ always_on: Optional[bool]
70
+ visibility: Optional[Visibility]
71
+
72
+ class PolyClientFunction(PolyDeployable):
73
+ logs_enabled: Optional[bool]
74
+ visibility: Optional[Visibility]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polyapi-python
3
- Version: 0.3.1.dev0
3
+ Version: 0.3.1.dev2
4
4
  Summary: The Python Client for PolyAPI, the IPaaS by Developers for Developers
5
5
  Author-email: Dan Fellin <dan@polyapi.io>
6
6
  License: MIT License
@@ -1,26 +1,30 @@
1
- polyapi/__init__.py,sha256=5iujRodfgRyLxT-zY0L3xax3rKRvfSt4NZlZYKOz03w,608
1
+ polyapi/__init__.py,sha256=a1Poy1kaTncYnUg6nWRcTjVm-R1CUQk12UX7VYQ9d5k,616
2
2
  polyapi/__main__.py,sha256=V4zhAh_YGxno5f_KSrlkELxcuDh9bR3WSd0n-2r-qQQ,93
3
3
  polyapi/api.py,sha256=e-8nOzq6SXD7_YPVBlW82_9wVxDCc8XD9ioMv_QvnH0,1877
4
4
  polyapi/auth.py,sha256=zrIGatjba5GwUTNjKj1GHQWTEDP9B-HrSzCKbLFoqvc,5336
5
- polyapi/cli.py,sha256=jgLbUTzMuLR-M5B21USyLQ42gpCBz-4Qz32DUSanvmM,3191
5
+ polyapi/cli.py,sha256=wXR5UE73nk26WQRbE8yK69h3h5udNrZFr85ORhbPnRs,8251
6
6
  polyapi/client.py,sha256=CoFDYvyKsqL4wPQbUDIr0Qb8Q5eD92xN4OEEcJEVuGQ,1296
7
7
  polyapi/config.py,sha256=uvEvOfWYZTLmBmZX-5jJxCzWPpwzVmEOIiQIdi98P4Y,3015
8
8
  polyapi/constants.py,sha256=sc-FnS0SngBLvSu1ZWMs0UCf9EYD1u1Yhfr-sZXGLns,607
9
+ polyapi/deployables.py,sha256=NihvDYrw7c-dB4Gfzwo7kiN2r4S74hs0azLuAPKXIR4,11849
9
10
  polyapi/error_handler.py,sha256=I_e0iz6VM23FLVQWJljxs2NGcl_OODbi43OcbnqBlp8,2398
10
11
  polyapi/exceptions.py,sha256=Zh7i7eCUhDuXEdUYjatkLFTeZkrx1BJ1P5ePgbJ9eIY,89
11
12
  polyapi/execute.py,sha256=kXnvlNQ7nz9cRlV2_5gXH09UCmyiDP5zi3wiAw0uDuk,1943
12
- polyapi/function_cli.py,sha256=kjWPS0of0Pwt4E8Tz4B5pJp1KT-t9swei4cHOF65-40,10352
13
- polyapi/generate.py,sha256=LN2Z6fE-HfpMsXlkJfOl8bqZdR3fUythE_ZsAe15tmk,8012
13
+ polyapi/function_cli.py,sha256=TDoSuhj7lkx3LZfI4ndL0v1VJrKm-UNycoAO5EpZydA,4147
14
+ polyapi/generate.py,sha256=SIRfN7RF3Z7eQ8kSNg4H70LeT7Hmh-Mn5maibvM7kAM,7969
15
+ polyapi/parser.py,sha256=ySPA-pFllc-UuRc1vN3xuDqGSGZR1uo90Lk0VP_v5ak,20130
16
+ polyapi/prepare.py,sha256=s1FSAo4bSs7GXu6n49Hz3abxFrFGL5RZtx8TH6ftcYU,6378
14
17
  polyapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
18
  polyapi/rendered_spec.py,sha256=uaNzBhP4cX7iGfKwzZv0dxMagWzsGeDr0cQYx_AyIhQ,2153
16
19
  polyapi/schema.py,sha256=VVMHAT5yU47cRC7xF44BrmUSemlk5oIKSxH2HTVPaQ8,3169
17
20
  polyapi/server.py,sha256=NzQCZFSAJK7XiRw1kiU_i9uMvgYK7i8qh7UX2xjytJU,1908
18
- polyapi/typedefs.py,sha256=mRqwd2LKofxNn_VSKxBzixni2j-tai8mfTQ0Wi2aLNM,1487
21
+ polyapi/sync.py,sha256=JZ0Q8QCu8IgdwDIhO8PtDPagcmVanrtGqJIMdLDmai4,5051
22
+ polyapi/typedefs.py,sha256=jmKprGFQSxmJXvwV53p-MFMcStmTp-tsgsynWjoVmU0,1986
19
23
  polyapi/utils.py,sha256=jzCh-ivKMcgp5fIXynhYmP9UyzsISr9bGGEzdPP8n3w,7644
20
24
  polyapi/variables.py,sha256=d36-trnfTL_8m2NkorMiImb4O3UrJbiFV38CHxV5i0A,4200
21
25
  polyapi/webhook.py,sha256=LWv28c2MLz_OKBI_Nn7WR4C-gs1SWgbdXsoxIIf-9UI,4886
22
- polyapi_python-0.3.1.dev0.dist-info/LICENSE,sha256=Hi0kDr56Dsy0uYIwNt4r9G7tI8x8miXRTlyvbeplCP8,1068
23
- polyapi_python-0.3.1.dev0.dist-info/METADATA,sha256=eR-BM5nhjyNoBBqZzTzKT4-aFChlKnlWBJ9y8775k4w,5326
24
- polyapi_python-0.3.1.dev0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
25
- polyapi_python-0.3.1.dev0.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
26
- polyapi_python-0.3.1.dev0.dist-info/RECORD,,
26
+ polyapi_python-0.3.1.dev2.dist-info/LICENSE,sha256=Hi0kDr56Dsy0uYIwNt4r9G7tI8x8miXRTlyvbeplCP8,1068
27
+ polyapi_python-0.3.1.dev2.dist-info/METADATA,sha256=Q24DhrHmmS0oO4ZV3rfRqWnnyEq-nP_aWTedjzI4A94,5326
28
+ polyapi_python-0.3.1.dev2.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
29
+ polyapi_python-0.3.1.dev2.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
30
+ polyapi_python-0.3.1.dev2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.5.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5