polyapi-python 0.3.8.dev7__py3-none-any.whl → 0.3.8.dev8__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/generate.py CHANGED
@@ -2,6 +2,8 @@ import json
2
2
  import requests
3
3
  import os
4
4
  import shutil
5
+ import logging
6
+ import tempfile
5
7
  from typing import Any, List, Optional, Tuple, cast
6
8
 
7
9
  from .auth import render_auth_function
@@ -426,48 +428,124 @@ def add_function_file(
426
428
  function_name: str,
427
429
  spec: SpecificationDto,
428
430
  ):
429
- # first lets add the import to the __init__
430
- init_the_init(full_path)
431
+ """
432
+ Atomically add a function file to prevent partial corruption during generation failures.
433
+
434
+ This function generates all content first, then writes files atomically using temporary files
435
+ to ensure that either the entire operation succeeds or no changes are made to the filesystem.
436
+ """
437
+ try:
438
+ # first lets add the import to the __init__
439
+ init_the_init(full_path)
431
440
 
432
- func_str, func_type_defs = render_spec(spec)
441
+ func_str, func_type_defs = render_spec(spec)
433
442
 
434
- if func_str:
435
- # add function to init
436
- init_path = os.path.join(full_path, "__init__.py")
437
- with open(init_path, "a") as f:
438
- f.write(f"\n\nfrom . import {to_func_namespace(function_name)}\n\n{func_str}")
443
+ if not func_str:
444
+ # If render_spec failed and returned empty string, don't create any files
445
+ raise Exception("Function rendering failed - empty function string returned")
439
446
 
440
- # add type_defs to underscore file
441
- file_path = os.path.join(full_path, f"{to_func_namespace(function_name)}.py")
442
- with open(file_path, "w") as f:
443
- f.write(func_type_defs)
447
+ # Prepare all content first before writing any files
448
+ func_namespace = to_func_namespace(function_name)
449
+ init_path = os.path.join(full_path, "__init__.py")
450
+ func_file_path = os.path.join(full_path, f"{func_namespace}.py")
451
+
452
+ # Read current __init__.py content if it exists
453
+ init_content = ""
454
+ if os.path.exists(init_path):
455
+ with open(init_path, "r") as f:
456
+ init_content = f.read()
457
+
458
+ # Prepare new content to append to __init__.py
459
+ new_init_content = init_content + f"\n\nfrom . import {func_namespace}\n\n{func_str}"
460
+
461
+ # Use temporary files for atomic writes
462
+ # Write to __init__.py atomically
463
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, dir=full_path, suffix=".tmp") as temp_init:
464
+ temp_init.write(new_init_content)
465
+ temp_init_path = temp_init.name
466
+
467
+ # Write to function file atomically
468
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, dir=full_path, suffix=".tmp") as temp_func:
469
+ temp_func.write(func_type_defs)
470
+ temp_func_path = temp_func.name
471
+
472
+ # Atomic operations: move temp files to final locations
473
+ shutil.move(temp_init_path, init_path)
474
+ shutil.move(temp_func_path, func_file_path)
475
+
476
+ except Exception as e:
477
+ # Clean up any temporary files that might have been created
478
+ try:
479
+ if 'temp_init_path' in locals() and os.path.exists(temp_init_path):
480
+ os.unlink(temp_init_path)
481
+ if 'temp_func_path' in locals() and os.path.exists(temp_func_path):
482
+ os.unlink(temp_func_path)
483
+ except:
484
+ pass # Best effort cleanup
485
+
486
+ # Re-raise the original exception
487
+ raise e
444
488
 
445
489
 
446
490
  def create_function(
447
491
  spec: SpecificationDto
448
492
  ) -> None:
493
+ """
494
+ Create a function with atomic directory and file operations.
495
+
496
+ Tracks directory creation to enable cleanup on failure.
497
+ """
449
498
  full_path = os.path.dirname(os.path.abspath(__file__))
450
499
  folders = f"poly.{spec['context']}.{spec['name']}".split(".")
451
- for idx, folder in enumerate(folders):
452
- if idx + 1 == len(folders):
453
- # special handling for final level
454
- add_function_file(
455
- full_path,
456
- folder,
457
- spec,
458
- )
459
- else:
460
- full_path = os.path.join(full_path, folder)
461
- if not os.path.exists(full_path):
462
- os.makedirs(full_path)
463
-
464
- # append to __init__.py file if nested folders
465
- next = folders[idx + 1] if idx + 2 < len(folders) else ""
466
- if next:
467
- init_the_init(full_path)
468
- add_import_to_init(full_path, next)
500
+ created_dirs = [] # Track directories we create for cleanup on failure
501
+
502
+ try:
503
+ for idx, folder in enumerate(folders):
504
+ if idx + 1 == len(folders):
505
+ # special handling for final level
506
+ add_function_file(
507
+ full_path,
508
+ folder,
509
+ spec,
510
+ )
511
+ else:
512
+ full_path = os.path.join(full_path, folder)
513
+ if not os.path.exists(full_path):
514
+ os.makedirs(full_path)
515
+ created_dirs.append(full_path) # Track for cleanup
516
+
517
+ # append to __init__.py file if nested folders
518
+ next = folders[idx + 1] if idx + 2 < len(folders) else ""
519
+ if next:
520
+ init_the_init(full_path)
521
+ add_import_to_init(full_path, next)
522
+
523
+ except Exception as e:
524
+ # Clean up directories we created (in reverse order)
525
+ for dir_path in reversed(created_dirs):
526
+ try:
527
+ if os.path.exists(dir_path) and not os.listdir(dir_path): # Only remove if empty
528
+ os.rmdir(dir_path)
529
+ except:
530
+ pass # Best effort cleanup
531
+
532
+ # Re-raise the original exception
533
+ raise e
469
534
 
470
535
 
471
536
  def generate_functions(functions: List[SpecificationDto]) -> None:
537
+ failed_functions = []
472
538
  for func in functions:
473
- create_function(func)
539
+ try:
540
+ create_function(func)
541
+ except Exception as e:
542
+ function_path = f"{func.get('context', 'unknown')}.{func.get('name', 'unknown')}"
543
+ function_id = func.get('id', 'unknown')
544
+ failed_functions.append(f"{function_path} (id: {function_id})")
545
+ logging.warning(f"WARNING: Failed to generate function {function_path} (id: {function_id}): {str(e)}")
546
+ continue
547
+
548
+ if failed_functions:
549
+ logging.warning(f"WARNING: {len(failed_functions)} function(s) failed to generate:")
550
+ for failed_func in failed_functions:
551
+ logging.warning(f" - {failed_func}")
polyapi/poly_schemas.py CHANGED
@@ -1,4 +1,7 @@
1
1
  import os
2
+ import logging
3
+ import tempfile
4
+ import shutil
2
5
  from typing import Any, Dict, List, Tuple
3
6
 
4
7
  from polyapi.schema import wrapped_generate_schema_types
@@ -21,13 +24,33 @@ FALLBACK_SPEC_TEMPLATE = """class {name}(TypedDict, total=False):
21
24
 
22
25
 
23
26
  def generate_schemas(specs: List[SchemaSpecDto], limit_ids: List[str] = None):
27
+ failed_schemas = []
24
28
  if limit_ids:
25
29
  for spec in specs:
26
30
  if spec["id"] in limit_ids:
27
- create_schema(spec)
31
+ try:
32
+ create_schema(spec)
33
+ except Exception as e:
34
+ schema_path = f"{spec.get('context', 'unknown')}.{spec.get('name', 'unknown')}"
35
+ schema_id = spec.get('id', 'unknown')
36
+ failed_schemas.append(f"{schema_path} (id: {schema_id})")
37
+ logging.warning(f"WARNING: Failed to generate schema {schema_path} (id: {schema_id}): {str(e)}")
38
+ continue
28
39
  else:
29
40
  for spec in specs:
30
- create_schema(spec)
41
+ try:
42
+ create_schema(spec)
43
+ except Exception as e:
44
+ schema_path = f"{spec.get('context', 'unknown')}.{spec.get('name', 'unknown')}"
45
+ schema_id = spec.get('id', 'unknown')
46
+ failed_schemas.append(f"{schema_path} (id: {schema_id})")
47
+ logging.warning(f"WARNING: Failed to generate schema {schema_path} (id: {schema_id}): {str(e)}")
48
+ continue
49
+
50
+ if failed_schemas:
51
+ logging.warning(f"WARNING: {len(failed_schemas)} schema(s) failed to generate:")
52
+ for failed_schema in failed_schemas:
53
+ logging.warning(f" - {failed_schema}")
31
54
 
32
55
 
33
56
  def add_schema_file(
@@ -35,51 +58,114 @@ def add_schema_file(
35
58
  schema_name: str,
36
59
  spec: SchemaSpecDto,
37
60
  ):
38
- # first lets add the import to the __init__
39
- init_the_init(full_path, SCHEMA_CODE_IMPORTS)
40
-
41
- if not spec["definition"].get("title"):
42
- # very empty schemas like mews.Unit are possible
43
- # add a title here to be sure they render
44
- spec["definition"]["title"] = schema_name
45
-
46
- schema_defs = render_poly_schema(spec)
47
-
48
- if schema_defs:
49
- # add function to init
61
+ """
62
+ Atomically add a schema file to prevent partial corruption during generation failures.
63
+
64
+ This function generates all content first, then writes files atomically using temporary files
65
+ to ensure that either the entire operation succeeds or no changes are made to the filesystem.
66
+ """
67
+ try:
68
+ # first lets add the import to the __init__
69
+ init_the_init(full_path, SCHEMA_CODE_IMPORTS)
70
+
71
+ if not spec["definition"].get("title"):
72
+ # very empty schemas like mews.Unit are possible
73
+ # add a title here to be sure they render
74
+ spec["definition"]["title"] = schema_name
75
+
76
+ schema_defs = render_poly_schema(spec)
77
+
78
+ if not schema_defs:
79
+ # If render_poly_schema failed and returned empty string, don't create any files
80
+ raise Exception("Schema rendering failed - empty schema content returned")
81
+
82
+ # Prepare all content first before writing any files
83
+ schema_namespace = to_func_namespace(schema_name)
50
84
  init_path = os.path.join(full_path, "__init__.py")
51
- with open(init_path, "a") as f:
52
- f.write(f"\n\nfrom ._{to_func_namespace(schema_name)} import {schema_name}\n__all__.append('{schema_name}')\n")
53
-
54
- # add type_defs to underscore file
55
- file_path = os.path.join(full_path, f"_{to_func_namespace(schema_name)}.py")
56
- with open(file_path, "w") as f:
57
- f.write(schema_defs)
85
+ schema_file_path = os.path.join(full_path, f"_{schema_namespace}.py")
86
+
87
+ # Read current __init__.py content if it exists
88
+ init_content = ""
89
+ if os.path.exists(init_path):
90
+ with open(init_path, "r") as f:
91
+ init_content = f.read()
92
+
93
+ # Prepare new content to append to __init__.py
94
+ new_init_content = init_content + f"\n\nfrom ._{schema_namespace} import {schema_name}\n__all__.append('{schema_name}')\n"
95
+
96
+ # Use temporary files for atomic writes
97
+ # Write to __init__.py atomically
98
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, dir=full_path, suffix=".tmp") as temp_init:
99
+ temp_init.write(new_init_content)
100
+ temp_init_path = temp_init.name
101
+
102
+ # Write to schema file atomically
103
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, dir=full_path, suffix=".tmp") as temp_schema:
104
+ temp_schema.write(schema_defs)
105
+ temp_schema_path = temp_schema.name
106
+
107
+ # Atomic operations: move temp files to final locations
108
+ shutil.move(temp_init_path, init_path)
109
+ shutil.move(temp_schema_path, schema_file_path)
110
+
111
+ except Exception as e:
112
+ # Clean up any temporary files that might have been created
113
+ try:
114
+ if 'temp_init_path' in locals() and os.path.exists(temp_init_path):
115
+ os.unlink(temp_init_path)
116
+ if 'temp_schema_path' in locals() and os.path.exists(temp_schema_path):
117
+ os.unlink(temp_schema_path)
118
+ except:
119
+ pass # Best effort cleanup
120
+
121
+ # Re-raise the original exception
122
+ raise e
58
123
 
59
124
 
60
125
  def create_schema(
61
126
  spec: SchemaSpecDto
62
127
  ) -> None:
128
+ """
129
+ Create a schema with atomic directory and file operations.
130
+
131
+ Tracks directory creation to enable cleanup on failure.
132
+ """
63
133
  full_path = os.path.dirname(os.path.abspath(__file__))
64
134
  folders = f"schemas.{spec['context']}.{spec['name']}".split(".")
65
- for idx, folder in enumerate(folders):
66
- if idx + 1 == len(folders):
67
- # special handling for final level
68
- add_schema_file(
69
- full_path,
70
- folder,
71
- spec,
72
- )
73
- else:
74
- full_path = os.path.join(full_path, folder)
75
- if not os.path.exists(full_path):
76
- os.makedirs(full_path)
77
-
78
- # append to __init__.py file if nested folders
79
- next = folders[idx + 1] if idx + 2 < len(folders) else ""
80
- if next:
81
- init_the_init(full_path, SCHEMA_CODE_IMPORTS)
82
- add_import_to_init(full_path, next)
135
+ created_dirs = [] # Track directories we create for cleanup on failure
136
+
137
+ try:
138
+ for idx, folder in enumerate(folders):
139
+ if idx + 1 == len(folders):
140
+ # special handling for final level
141
+ add_schema_file(
142
+ full_path,
143
+ folder,
144
+ spec,
145
+ )
146
+ else:
147
+ full_path = os.path.join(full_path, folder)
148
+ if not os.path.exists(full_path):
149
+ os.makedirs(full_path)
150
+ created_dirs.append(full_path) # Track for cleanup
151
+
152
+ # append to __init__.py file if nested folders
153
+ next = folders[idx + 1] if idx + 2 < len(folders) else ""
154
+ if next:
155
+ init_the_init(full_path, SCHEMA_CODE_IMPORTS)
156
+ add_import_to_init(full_path, next)
157
+
158
+ except Exception as e:
159
+ # Clean up directories we created (in reverse order)
160
+ for dir_path in reversed(created_dirs):
161
+ try:
162
+ if os.path.exists(dir_path) and not os.listdir(dir_path): # Only remove if empty
163
+ os.rmdir(dir_path)
164
+ except:
165
+ pass # Best effort cleanup
166
+
167
+ # Re-raise the original exception
168
+ raise e
83
169
 
84
170
 
85
171
  def add_schema_to_init(full_path: str, spec: SchemaSpecDto):
polyapi/variables.py CHANGED
@@ -1,4 +1,7 @@
1
1
  import os
2
+ import logging
3
+ import tempfile
4
+ import shutil
2
5
  from typing import List
3
6
 
4
7
  from polyapi.schema import map_primitive_types
@@ -70,8 +73,21 @@ class {variable_name}:{get_method}
70
73
 
71
74
 
72
75
  def generate_variables(variables: List[VariableSpecDto]):
76
+ failed_variables = []
73
77
  for variable in variables:
74
- create_variable(variable)
78
+ try:
79
+ create_variable(variable)
80
+ except Exception as e:
81
+ variable_path = f"{variable.get('context', 'unknown')}.{variable.get('name', 'unknown')}"
82
+ variable_id = variable.get('id', 'unknown')
83
+ failed_variables.append(f"{variable_path} (id: {variable_id})")
84
+ logging.warning(f"WARNING: Failed to generate variable {variable_path} (id: {variable_id}): {str(e)}")
85
+ continue
86
+
87
+ if failed_variables:
88
+ logging.warning(f"WARNING: {len(failed_variables)} variable(s) failed to generate:")
89
+ for failed_var in failed_variables:
90
+ logging.warning(f" - {failed_var}")
75
91
 
76
92
 
77
93
  def render_variable(variable: VariableSpecDto):
@@ -116,26 +132,84 @@ def _get_variable_type(type_spec: PropertyType) -> str:
116
132
 
117
133
 
118
134
  def create_variable(variable: VariableSpecDto) -> None:
135
+ """
136
+ Create a variable with atomic directory and file operations.
137
+
138
+ Tracks directory creation to enable cleanup on failure.
139
+ """
119
140
  folders = ["vari"]
120
141
  if variable["context"]:
121
142
  folders += variable["context"].split(".")
122
143
 
123
144
  # build up the full_path by adding all the folders
124
145
  full_path = os.path.join(os.path.dirname(os.path.abspath(__file__)))
125
-
126
- for idx, folder in enumerate(folders):
127
- full_path = os.path.join(full_path, folder)
128
- if not os.path.exists(full_path):
129
- os.makedirs(full_path)
130
- next = folders[idx + 1] if idx + 1 < len(folders) else None
131
- if next:
132
- add_import_to_init(full_path, next)
133
-
134
- add_variable_to_init(full_path, variable)
146
+ created_dirs = [] # Track directories we create for cleanup on failure
147
+
148
+ try:
149
+ for idx, folder in enumerate(folders):
150
+ full_path = os.path.join(full_path, folder)
151
+ if not os.path.exists(full_path):
152
+ os.makedirs(full_path)
153
+ created_dirs.append(full_path) # Track for cleanup
154
+ next = folders[idx + 1] if idx + 1 < len(folders) else None
155
+ if next:
156
+ add_import_to_init(full_path, next)
157
+
158
+ add_variable_to_init(full_path, variable)
159
+
160
+ except Exception as e:
161
+ # Clean up directories we created (in reverse order)
162
+ for dir_path in reversed(created_dirs):
163
+ try:
164
+ if os.path.exists(dir_path) and not os.listdir(dir_path): # Only remove if empty
165
+ os.rmdir(dir_path)
166
+ except:
167
+ pass # Best effort cleanup
168
+
169
+ # Re-raise the original exception
170
+ raise e
135
171
 
136
172
 
137
173
  def add_variable_to_init(full_path: str, variable: VariableSpecDto):
138
- init_the_init(full_path)
139
- init_path = os.path.join(full_path, "__init__.py")
140
- with open(init_path, "a") as f:
141
- f.write(render_variable(variable) + "\n\n")
174
+ """
175
+ Atomically add a variable to __init__.py to prevent partial corruption during generation failures.
176
+
177
+ This function generates all content first, then writes the file atomically using temporary files
178
+ to ensure that either the entire operation succeeds or no changes are made to the filesystem.
179
+ """
180
+ try:
181
+ init_the_init(full_path)
182
+ init_path = os.path.join(full_path, "__init__.py")
183
+
184
+ # Generate variable content first
185
+ variable_content = render_variable(variable)
186
+ if not variable_content:
187
+ raise Exception("Variable rendering failed - empty content returned")
188
+
189
+ # Read current __init__.py content if it exists
190
+ init_content = ""
191
+ if os.path.exists(init_path):
192
+ with open(init_path, "r") as f:
193
+ init_content = f.read()
194
+
195
+ # Prepare new content to append
196
+ new_init_content = init_content + variable_content + "\n\n"
197
+
198
+ # Write to temporary file first, then atomic move
199
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, dir=full_path, suffix=".tmp") as temp_file:
200
+ temp_file.write(new_init_content)
201
+ temp_file_path = temp_file.name
202
+
203
+ # Atomic operation: move temp file to final location
204
+ shutil.move(temp_file_path, init_path)
205
+
206
+ except Exception as e:
207
+ # Clean up temporary file if it exists
208
+ try:
209
+ if 'temp_file_path' in locals() and os.path.exists(temp_file_path):
210
+ os.unlink(temp_file_path)
211
+ except:
212
+ pass # Best effort cleanup
213
+
214
+ # Re-raise the original exception
215
+ raise e
polyapi/webhook.py CHANGED
@@ -2,6 +2,7 @@ import asyncio
2
2
  import socketio # type: ignore
3
3
  from socketio.exceptions import ConnectionError # type: ignore
4
4
  import uuid
5
+ import logging
5
6
  from typing import Any, Dict, List, Tuple
6
7
 
7
8
  from polyapi.config import get_api_key_and_url
@@ -121,22 +122,27 @@ def render_webhook_handle(
121
122
  arguments: List[PropertySpecification],
122
123
  return_type: Dict[str, Any],
123
124
  ) -> Tuple[str, str]:
124
- function_args, function_args_def = parse_arguments(function_name, arguments)
125
-
126
- if "WebhookEventType" in function_args:
127
- # let's add the function name import!
128
- function_args = function_args.replace("WebhookEventType", f"{to_func_namespace(function_name)}.WebhookEventType")
129
-
130
- func_str = WEBHOOK_TEMPLATE.format(
131
- description=function_description,
132
- client_id=uuid.uuid4().hex,
133
- function_id=function_id,
134
- function_name=function_name,
135
- function_args=function_args,
136
- function_path=poly_full_path(function_context, function_name),
137
- )
138
- func_defs = WEBHOOK_DEFS_TEMPLATE.format(function_args_def=function_args_def)
139
- return func_str, func_defs
125
+ try:
126
+ function_args, function_args_def = parse_arguments(function_name, arguments)
127
+
128
+ if "WebhookEventType" in function_args:
129
+ # let's add the function name import!
130
+ function_args = function_args.replace("WebhookEventType", f"{to_func_namespace(function_name)}.WebhookEventType")
131
+
132
+ func_str = WEBHOOK_TEMPLATE.format(
133
+ description=function_description,
134
+ client_id=uuid.uuid4().hex,
135
+ function_id=function_id,
136
+ function_name=function_name,
137
+ function_args=function_args,
138
+ function_path=poly_full_path(function_context, function_name),
139
+ )
140
+ func_defs = WEBHOOK_DEFS_TEMPLATE.format(function_args_def=function_args_def)
141
+ return func_str, func_defs
142
+ except Exception as e:
143
+ logging.warning(f"Failed to render webhook handle {function_context}.{function_name} (id: {function_id}): {str(e)}")
144
+ # Return empty strings to indicate generation failure - this will be caught by generate_functions error handling
145
+ return "", ""
140
146
 
141
147
 
142
148
  def start(*args):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyapi-python
3
- Version: 0.3.8.dev7
3
+ Version: 0.3.8.dev8
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
@@ -11,9 +11,9 @@ polyapi/error_handler.py,sha256=I_e0iz6VM23FLVQWJljxs2NGcl_OODbi43OcbnqBlp8,2398
11
11
  polyapi/exceptions.py,sha256=Zh7i7eCUhDuXEdUYjatkLFTeZkrx1BJ1P5ePgbJ9eIY,89
12
12
  polyapi/execute.py,sha256=sjI6BMBYPSCD6UngV9DzpJIRSU6p02aShNaTXhDExtY,3457
13
13
  polyapi/function_cli.py,sha256=H0sVrbvRBXw_xeApe2MvQw8p_xE7jVTTOU-07Dg041A,4220
14
- polyapi/generate.py,sha256=rzRb9TW5VjdqT13beIezQratdfAvE7yYWX_ODlZJTK0,16105
14
+ polyapi/generate.py,sha256=slCw9AOvQHQ8UtEaumFI1NoRvjH2Dj3Y33u7imQqi8c,19521
15
15
  polyapi/parser.py,sha256=mdoh4pNq8pyiHE0-i6Coqj8frEXfBLRk6itpAXMrrgI,20373
16
- polyapi/poly_schemas.py,sha256=T4kfZyfgVLiqLD28GmYNiHnrNx77J_HO4uzk8LUAhlo,3137
16
+ polyapi/poly_schemas.py,sha256=TC_pCuK2lGCxEruW-og4fcQzliPZEbCGzrjAOLB-kXw,7061
17
17
  polyapi/prepare.py,sha256=pRWBhpgqMtKP04P9F6PIA3eCkOpCxQSv9TZdR3qR34I,7216
18
18
  polyapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  polyapi/rendered_spec.py,sha256=nJEj2vRgG3N20fU4s-ThRtOIwAuTzXwXuOBIkXljDVc,2240
@@ -22,10 +22,10 @@ polyapi/server.py,sha256=YXWxhYBx-hluwDQ8Jvfpy2s8ogz0GsNTMcZVNcP5ca8,2147
22
22
  polyapi/sync.py,sha256=PGdC0feBBjEVrF3d9EluW_OAxbWuzSrfh84czma8kWg,6476
23
23
  polyapi/typedefs.py,sha256=MGDwWaijLNqokXF9UCHGAP-yKixOzztrH4Lsj800AJs,2328
24
24
  polyapi/utils.py,sha256=1F7Dwst_PbPuUBUSxx5r8d2DHDgqHtu07QW92T_YSdw,12454
25
- polyapi/variables.py,sha256=j7WWrGLr2O5SkWGxnsusnnfl25kVL3b6SQYcVGEoC8c,4277
26
- polyapi/webhook.py,sha256=NTSXYOl_QqsFekWRepPyVTsV9SVkgUu0HfG1SJJDHOE,4958
27
- polyapi_python-0.3.8.dev7.dist-info/licenses/LICENSE,sha256=6b_I7aPVp8JXhqQwdw7_B84Ca0S4JGjHj0sr_1VOdB4,1068
28
- polyapi_python-0.3.8.dev7.dist-info/METADATA,sha256=S-3sPHx5CGUd7gA-H-RWrt7XbzrSrerg0GgRAJhgdQw,5782
29
- polyapi_python-0.3.8.dev7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
- polyapi_python-0.3.8.dev7.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
31
- polyapi_python-0.3.8.dev7.dist-info/RECORD,,
25
+ polyapi/variables.py,sha256=VAp2d5I-4WLYHCPF1w3pqU4-z8_XRQpYW-ddOw6G5S4,7268
26
+ polyapi/webhook.py,sha256=gWYXHz0PnB_uY_lnHeUlg3EIHfTGwF-Tc6UaatldZBw,5333
27
+ polyapi_python-0.3.8.dev8.dist-info/licenses/LICENSE,sha256=6b_I7aPVp8JXhqQwdw7_B84Ca0S4JGjHj0sr_1VOdB4,1068
28
+ polyapi_python-0.3.8.dev8.dist-info/METADATA,sha256=3atDYIJdS2MOsB14rghtBE4hBlCsfsaNDZHwmYIol4Q,5782
29
+ polyapi_python-0.3.8.dev8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
+ polyapi_python-0.3.8.dev8.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
31
+ polyapi_python-0.3.8.dev8.dist-info/RECORD,,