polyapi-python 0.3.13__py3-none-any.whl → 0.3.13.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/poly_tables.py CHANGED
@@ -1,64 +1,27 @@
1
1
  import os
2
2
  import requests
3
3
  from typing_extensions import NotRequired, TypedDict
4
- from typing import (
5
- List,
6
- Union,
7
- Type,
8
- Dict,
9
- Any,
10
- Literal,
11
- Tuple,
12
- Optional,
13
- get_args,
14
- get_origin,
15
- )
4
+ from typing import List, Union, Type, Dict, Any, Literal, Tuple, Optional, get_args, get_origin
16
5
  from polyapi.utils import add_import_to_init, init_the_init
17
6
  from polyapi.typedefs import TableSpecDto
18
7
  from polyapi.constants import JSONSCHEMA_TO_PYTHON_TYPE_MAP
19
- from polyapi.config import get_api_key_and_url
20
8
 
21
- TABI_MODULE_IMPORTS = "\n".join(
22
- [
23
- "from typing_extensions import NotRequired, TypedDict",
24
- "from typing import Union, List, Dict, Any, Literal, Optional, Required, overload",
25
- "from polyapi.poly_tables import execute_query, first_result, transform_query, delete_one_response",
26
- "from polyapi.typedefs import Table, PolyCountResult, PolyDeleteResult, PolyDeleteResults, SortOrder, StringFilter, NullableStringFilter, NumberFilter, NullableNumberFilter, BooleanFilter, NullableBooleanFilter, NullableObjectFilter",
27
- ]
28
- )
29
-
30
-
31
- def scrub(data: Any) -> Any:
32
- if not data or not isinstance(data, (Dict, List)):
33
- return data
9
+ def scrub(data) -> Dict[str, Any]:
10
+ if (not data or not isinstance(data, (Dict, List))): return data
34
11
  if isinstance(data, List):
35
12
  return [scrub(item) for item in data]
36
13
  else:
37
14
  temp = {}
38
- secrets = [
39
- "x_api_key",
40
- "x-api-key",
41
- "access_token",
42
- "access-token",
43
- "authorization",
44
- "api_key",
45
- "api-key",
46
- "apikey",
47
- "accesstoken",
48
- "token",
49
- "password",
50
- "key",
51
- ]
15
+ secrets = ["x_api_key", "x-api-key", "access_token", "access-token", "authorization", "api_key", "api-key", "apikey", "accesstoken", "token", "password", "key"]
52
16
  for key, value in data.items():
53
17
  if isinstance(value, (Dict, List)):
54
18
  temp[key] = scrub(data[key])
55
19
  elif key.lower() in secrets:
56
- temp[key] = "********"
20
+ temp[key] = '********'
57
21
  else:
58
22
  temp[key] = data[key]
59
23
  return temp
60
24
 
61
-
62
25
  def scrub_keys(e: Exception) -> Dict[str, Any]:
63
26
  """
64
27
  Scrub the keys of an exception to remove sensitive information.
@@ -68,26 +31,18 @@ def scrub_keys(e: Exception) -> Dict[str, Any]:
68
31
  "error": str(e),
69
32
  "type": type(e).__name__,
70
33
  "message": str(e),
71
- "args": scrub(getattr(e, "args", None)),
34
+ "args": scrub(getattr(e, 'args', None))
72
35
  }
73
36
 
74
37
 
75
38
  def execute_query(table_id, method, query):
76
39
  from polyapi import polyCustom
77
40
  from polyapi.poly.client_id import client_id
78
-
79
41
  try:
80
- api_key, base_url = get_api_key_and_url()
81
- if not base_url:
82
- raise ValueError(
83
- "PolyAPI Instance URL is not configured, run `python -m polyapi setup`."
84
- )
85
-
86
- auth_key = polyCustom.get("executionApiKey") or api_key
87
- url = f"{base_url.rstrip('/')}/tables/{table_id}/{method}?clientId={client_id}"
88
- headers = {"x-poly-execution-id": polyCustom.get("executionId")}
89
- if auth_key:
90
- headers["Authorization"] = f"Bearer {auth_key}"
42
+ url = f"/tables/{table_id}/{method}?clientId={client_id}"
43
+ headers = {{
44
+ 'x-poly-execution-id': polyCustom.get('executionId')
45
+ }}
91
46
  response = requests.post(url, json=query, headers=headers)
92
47
  response.raise_for_status()
93
48
  return response.json()
@@ -96,16 +51,14 @@ def execute_query(table_id, method, query):
96
51
 
97
52
 
98
53
  def first_result(rsp):
99
- if isinstance(rsp, dict) and isinstance(rsp.get("results"), list):
100
- return rsp["results"][0] if rsp["results"] else None
54
+ if isinstance(rsp, dict) and isinstance(rsp.get('results'), list):
55
+ return rsp['results'][0] if rsp['results'] else None
101
56
  return rsp
102
57
 
103
-
104
58
  def delete_one_response(rsp):
105
- if isinstance(rsp, dict) and isinstance(rsp.get("deleted"), int):
106
- return {"deleted": bool(rsp.get("deleted"))}
107
- return {"deleted": False}
108
-
59
+ if isinstance(rsp, dict) and isinstance(rsp.get('deleted'), int):
60
+ return { 'deleted': bool(rsp.get('deleted')) }
61
+ return { 'deleted': false }
109
62
 
110
63
  _key_transform_map = {
111
64
  "not_": "not",
@@ -119,7 +72,8 @@ _key_transform_map = {
119
72
  def _transform_keys(obj: Any) -> Any:
120
73
  if isinstance(obj, dict):
121
74
  return {
122
- _key_transform_map.get(k, k): _transform_keys(v) for k, v in obj.items()
75
+ _key_transform_map.get(k, k): _transform_keys(v)
76
+ for k, v in obj.items()
123
77
  }
124
78
 
125
79
  elif isinstance(obj, list):
@@ -134,13 +88,13 @@ def transform_query(query: dict) -> dict:
134
88
  return {
135
89
  **query,
136
90
  "where": _transform_keys(query["where"]) if query["where"] else None,
137
- "orderBy": query["order_by"] if query["order_by"] else None,
91
+ "orderBy": query["order_by"] if query["order_by"] else None
138
92
  }
139
93
 
140
94
  return query
141
95
 
142
96
 
143
- TABI_TABLE_TEMPLATE = """
97
+ TABI_TABLE_TEMPLATE = '''
144
98
  {table_name}Columns = Literal[{table_columns}]
145
99
 
146
100
 
@@ -415,7 +369,7 @@ class {table_name}:{table_description}
415
369
  query["where"]["id"] = kwargs["id"]
416
370
  query.pop("id", None)
417
371
  return delete_one_response(execute_query({table_name}.table_id, "delete", transform_query(query)))
418
- """
372
+ '''
419
373
 
420
374
 
421
375
  def _get_column_type_str(name: str, schema: Dict[str, Any], is_required: bool) -> str:
@@ -423,17 +377,11 @@ def _get_column_type_str(name: str, schema: Dict[str, Any], is_required: bool) -
423
377
 
424
378
  col_type = schema.get("type", "object")
425
379
  if isinstance(col_type, list):
426
- subtypes = [
427
- _get_column_type_str(name, {**schema, "type": t}, is_required)
428
- for t in col_type
429
- ]
380
+ subtypes = [_get_column_type_str(name, { **schema, "type": t }, is_required) for t in col_type]
430
381
  result = f"Union[{', '.join(subtypes)}]"
431
382
  elif col_type == "array":
432
383
  if isinstance(schema["items"], list):
433
- subtypes = [
434
- _get_column_type_str(f"{name}{i}", s, True)
435
- for i, s in enumerate(schema["items"])
436
- ]
384
+ subtypes = [_get_column_type_str(f"{name}{i}", s, True) for i, s in enumerate(schema["items"])]
437
385
  result = f"Tuple[{', '.join(subtypes)}]"
438
386
  elif isinstance(schema["items"], dict):
439
387
  result = f"List[{_get_column_type_str(name, schema['items'], True)}]"
@@ -443,10 +391,7 @@ def _get_column_type_str(name: str, schema: Dict[str, Any], is_required: bool) -
443
391
  if isinstance(schema.get("patternProperties"), dict):
444
392
  # TODO: Handle multiple pattern properties
445
393
  result = f"Dict[str, {_get_column_type_str(f'{name}_', schema['patternProperties'], True)}]"
446
- elif (
447
- isinstance(schema.get("properties"), dict)
448
- and len(schema["properties"].values()) > 0
449
- ):
394
+ elif isinstance(schema.get("properties"), dict) and len(schema["properties"].values()) > 0:
450
395
  # TODO: Handle x-poly-refs
451
396
  result = f'"{name}"'
452
397
  else:
@@ -468,32 +413,24 @@ def _render_table_row_classes(table_name: str, schema: Dict[str, Any]) -> str:
468
413
  return output[1].split("\n", 1)[1].strip()
469
414
 
470
415
 
471
- def _render_table_subset_class(
472
- table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]
473
- ) -> str:
416
+ def _render_table_subset_class(table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]) -> str:
474
417
  # Generate class which can match any subset of a table row
475
418
  lines = [f"class {table_name}Subset(TypedDict):"]
476
419
 
477
420
  for name, schema in columns:
478
- type_str = _get_column_type_str(
479
- f"_{table_name}Row{name}", schema, name in required
480
- )
421
+ type_str = _get_column_type_str(f"_{table_name}Row{name}", schema, name in required)
481
422
  lines.append(f" {name}: NotRequired[{type_str}]")
482
423
 
483
424
  return "\n".join(lines)
484
425
 
485
426
 
486
- def _render_table_where_class(
487
- table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]
488
- ) -> str:
427
+ def _render_table_where_class(table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]) -> str:
489
428
  # Generate class for the 'where' part of the query
490
429
  lines = [f"class {table_name}WhereFilter(TypedDict):"]
491
430
 
492
431
  for name, schema in columns:
493
432
  ftype_str = ""
494
- type_str = _get_column_type_str(
495
- f"_{table_name}Row{name}", schema, True
496
- ) # force required to avoid wrapping type in Optional[]
433
+ type_str = _get_column_type_str(f"_{table_name}Row{name}", schema, True) # force required to avoid wrapping type in Optional[]
497
434
  is_required = name in required
498
435
  if type_str == "bool":
499
436
  ftype_str = "BooleanFilter" if is_required else "NullableBooleanFilter"
@@ -508,34 +445,24 @@ def _render_table_where_class(
508
445
  if ftype_str:
509
446
  lines.append(f" {name}: NotRequired[Union[{type_str}, {ftype_str}]]")
510
447
 
511
- lines.append(
512
- f' AND: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]'
513
- )
448
+ lines.append(f' AND: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]')
514
449
  lines.append(f' OR: NotRequired[List["{table_name}WhereFilter"]]')
515
- lines.append(
516
- f' NOT: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]'
517
- )
450
+ lines.append(f' NOT: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]')
518
451
 
519
452
  return "\n".join(lines)
520
453
 
521
454
 
522
455
  def _render_table(table: TableSpecDto) -> str:
523
456
  columns = list(table["schema"]["properties"].items())
524
- required_columns = table["schema"].get("required", [])
457
+ required_colunms = table["schema"].get("required", [])
525
458
 
526
- table_columns = ",".join([f'"{k}"' for k, _ in columns])
459
+ table_columns = ",".join([ f'"{k}"' for k,_ in columns])
527
460
  table_row_classes = _render_table_row_classes(table["name"], table["schema"])
528
- table_row_subset_class = _render_table_subset_class(
529
- table["name"], columns, required_columns
530
- )
531
- table_where_class = _render_table_where_class(
532
- table["name"], columns, required_columns
533
- )
461
+ table_row_subset_class = _render_table_subset_class(table["name"], columns, required_colunms)
462
+ table_where_class = _render_table_where_class(table["name"], columns, required_colunms)
534
463
  if table.get("description", ""):
535
- table_description = '\n """'
536
- table_description += "\n ".join(
537
- table["description"].replace('"', "'").split("\n")
538
- )
464
+ table_description = '\n """'
465
+ table_description += '\n '.join(table["description"].replace('"', "'").split("\n"))
539
466
  table_description += '\n """'
540
467
  else:
541
468
  table_description = ""
@@ -575,7 +502,12 @@ def _create_table(table: TableSpecDto) -> None:
575
502
 
576
503
  init_path = os.path.join(full_path, "__init__.py")
577
504
 
578
- imports = TABI_MODULE_IMPORTS
505
+ imports = "\n".join([
506
+ "from typing_extensions import NotRequired, TypedDict",
507
+ "from typing import Union, List, Dict, Any, Literal, Optional, Required, overload",
508
+ "from polyapi.poly_tables import execute_query, first_result, transform_query",
509
+ "from polyapi.typedefs import Table, PolyCountResult, PolyDeleteResults, SortOrder, StringFilter, NullableStringFilter, NumberFilter, NullableNumberFilter, BooleanFilter, NullableBooleanFilter, NullableObjectFilter",
510
+ ])
579
511
  table_contents = _render_table(table)
580
512
 
581
513
  file_contents = ""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyapi-python
3
- Version: 0.3.13
3
+ Version: 0.3.13.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
@@ -185,14 +185,6 @@ This script is handy for checking for any mypy types:
185
185
 
186
186
  Please ignore \[name-defined\] errors for now. This is a known bug we are working to fix!
187
187
 
188
- ## Strategies for QA'ing Changes To Generate Or Other Core Functionality
189
-
190
- Our https://na1.polyapi.io has a large OOB catalog (as does eu1/na2). We also have several big internal PolyAPI projects with Python (message @eupharis if you need a pointer to which ones).
191
-
192
- Running `python -m polyapi generate` in all these projects and then checking the flake8 and check_mypy steps above is a great way to build confidence that the `generate` changes has no gotchas.
193
-
194
- Of course all this is in addition to the changes passing through normal unittests and integration tests!
195
-
196
188
  ## Support
197
189
 
198
190
  If you run into any issues or want help getting started with this project, please contact support@polyapi.io
@@ -14,7 +14,7 @@ polyapi/function_cli.py,sha256=W30yL2i152iZCr6zAU1CHKlDp_tt7kB2cGIXIxmWumk,4302
14
14
  polyapi/generate.py,sha256=0zVDEnKVZnbMNZ6O0SWAuDLHrBrkW01vFkjpf9wrQZo,21046
15
15
  polyapi/parser.py,sha256=pAkeuwp1Kn6bHXiIoj-DuXQ518PztQThIa8vztgsKLQ,21525
16
16
  polyapi/poly_schemas.py,sha256=fZ6AGvHcOKQJtlrzSuzeBNed5DxPMA2dJGdJvuFCHWM,9066
17
- polyapi/poly_tables.py,sha256=jwJpd_QBoIaFPcQRpCaxdwr82fIPHnTjj2-a9knNmJs,19709
17
+ polyapi/poly_tables.py,sha256=SrByuusS1aL7L7R8o28TEr4A-8AfMGGHCKLg-9vmnxc,18783
18
18
  polyapi/prepare.py,sha256=NQzpMIoakNovStvOGOmqSYIpTwiWXaweNSE9se10A2E,7420
19
19
  polyapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  polyapi/rendered_spec.py,sha256=nJEj2vRgG3N20fU4s-ThRtOIwAuTzXwXuOBIkXljDVc,2240
@@ -25,8 +25,8 @@ polyapi/typedefs.py,sha256=mfll-KrngOW0wzbvDNiIDaDkFMwbsT-MY5y5hzWj9RE,5642
25
25
  polyapi/utils.py,sha256=CZdGusrLOA-e4zb9aZ4aI-UkDPBoyu0-euWj7EE0Vk8,13323
26
26
  polyapi/variables.py,sha256=SJv106ePpQP5mx7Iiafl_shtFlE8FoaO9Q8lvw-3IRg,7270
27
27
  polyapi/webhook.py,sha256=0ceLwHNjNd2Yx_8MX5jOIxiQ5Lwhy2pe81ProAuKon0,5108
28
- polyapi_python-0.3.13.dist-info/licenses/LICENSE,sha256=6b_I7aPVp8JXhqQwdw7_B84Ca0S4JGjHj0sr_1VOdB4,1068
29
- polyapi_python-0.3.13.dist-info/METADATA,sha256=N1mm1PBVLueOCP9I-I7IhobuwDtXgED8jEJ20Etaz0g,5879
30
- polyapi_python-0.3.13.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
31
- polyapi_python-0.3.13.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
32
- polyapi_python-0.3.13.dist-info/RECORD,,
28
+ polyapi_python-0.3.13.dev2.dist-info/licenses/LICENSE,sha256=6b_I7aPVp8JXhqQwdw7_B84Ca0S4JGjHj0sr_1VOdB4,1068
29
+ polyapi_python-0.3.13.dev2.dist-info/METADATA,sha256=V7aP-XoLF773lEJkHtTwvl0yGWFpzuFkpQEHhKO-C10,5318
30
+ polyapi_python-0.3.13.dev2.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
31
+ polyapi_python-0.3.13.dev2.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
32
+ polyapi_python-0.3.13.dev2.dist-info/RECORD,,