Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
2a4b538
# Feature (2970): Update python client to support setup command (#22)
sudiptatj Oct 31, 2024
8723978
improve polyapi-python setup (#24)
eupharis Nov 4, 2024
7ece4d0
# Feature (3007): Update python -m polyapi function add --logs option…
sudiptatj Nov 4, 2024
e292e4e
Project Glide + Refactor main command line args parsing (#26)
aarongoin Nov 14, 2024
cd89d8a
fix for poly cache directory path construction
aarongoin Nov 18, 2024
a8c2f52
one more adjustment to the deployables cache directory so there can't…
aarongoin Nov 18, 2024
4a0277a
this better?
aarongoin Nov 18, 2024
571e85a
verbose logging on upload code to see what's failing in CI/CD
aarongoin Nov 18, 2024
dbbbe61
bumpity
aarongoin Nov 18, 2024
c03268e
whoops
aarongoin Nov 18, 2024
64c2e37
so close
aarongoin Nov 18, 2024
2f71748
better?
aarongoin Nov 18, 2024
57a2d40
okay this should be the fix
aarongoin Nov 18, 2024
0e78bd3
is it this?
aarongoin Nov 18, 2024
30b2a28
maybe
aarongoin Nov 18, 2024
156d3df
oh for the love of pete
aarongoin Nov 18, 2024
20d8982
whatever. might be a pypi issue
aarongoin Nov 19, 2024
37b421b
removing verbose logging
aarongoin Nov 19, 2024
4cc8a16
fixing bugs in sync command to use correct api urls
aarongoin Nov 19, 2024
aa0be64
update logging
aarongoin Nov 19, 2024
db8aec6
lint
aarongoin Nov 19, 2024
32a65d1
improved auth
aarongoin Nov 19, 2024
14cf1ce
last fix for function sync
aarongoin Nov 19, 2024
9d4824a
fix bug when comment arguments don't align with the function
aarongoin Nov 19, 2024
ffe19f0
try forcing the poly directory to exist
aarongoin Nov 20, 2024
0d32c4a
test logging
aarongoin Nov 20, 2024
8bbb2c7
remove debug logging
aarongoin Nov 20, 2024
2808c97
fixing project glide deployable types and bumping the version
aarongoin Nov 22, 2024
123f0b7
fixing missing arguments in python client function upload
aarongoin Nov 22, 2024
7dc7afe
fixing return type for trained functions
aarongoin Nov 22, 2024
e117f1e
fix bug preventing use of poly sync command locally
aarongoin Nov 22, 2024
d4a656f
next version of client!
eupharis Nov 26, 2024
7441019
EN #3183 allow null logs flag for python client (#28)
eneumann Dec 5, 2024
57e7369
let the typing_extensions versions increase to support latest openai …
eupharis Dec 6, 2024
03fd34c
update dependency in one more place
eupharis Dec 6, 2024
28a1c39
Some bug fixes for python client (#29)
aarongoin Dec 14, 2024
027ceb5
Merge branch 'main' into develop
eupharis Dec 23, 2024
4ff9ba9
0.3.2
eupharis Dec 23, 2024
e895ae9
add poly schemas support (#31)
eupharis Mar 24, 2025
d189377
update to v4
eupharis Mar 24, 2025
a140802
v4 everywhere
eupharis Mar 24, 2025
96f63c3
bump version
eupharis Mar 24, 2025
15eab87
add new version
eupharis Mar 24, 2025
3ad2607
remove warning, just go with any type for now
eupharis Mar 26, 2025
1479d39
better generate printed messages, fix generate bug after function add
eupharis Mar 26, 2025
7db1cbe
Update python version (#32)
dchiniquy Mar 27, 2025
a3f09cd
Update python image (#33)
dchiniquy Mar 27, 2025
19fafde
Rollback version
nahuel-polyapi Mar 27, 2025
fccbf1e
onward (#34)
eupharis Apr 8, 2025
1e947d6
next (#35)
eupharis Apr 8, 2025
11108e0
improve intellisense detection of schemas
eupharis Apr 11, 2025
ef7e5e9
release 0.3.3.dev8, fix misleading generate after setup
eupharis Apr 14, 2025
71e2332
0.3.3.dev9 - add support for optional arguments (#36)
eupharis Apr 14, 2025
2b4a2d0
next
eupharis Apr 15, 2025
2169e15
release 0.3.3.dev10
eupharis Apr 15, 2025
c2db3e9
EN #3943 update to support SFX serverSideAsync True by setting correc…
eneumann May 2, 2025
2fc69ea
deploying version 0.3.3 for R22
nahuel-polyapi May 6, 2025
1e683f2
Merge branch 'main' into develop
eupharis May 6, 2025
a4a4872
upgrade version
FedeMarchiniHotovo May 6, 2025
e0e74b7
Merge branch 'main' into develop
FedeMarchiniHotovo May 6, 2025
a6ba2f3
4084 - revert strippping none values from function arguments during e…
akinboboye May 7, 2025
9c1a2a1
P2) Update clients and specs endpoint so when generating with no-type…
RichardDzurus May 7, 2025
d20794b
4010 generate contexts (#43)
akinboboye May 8, 2025
d02bae3
make contexts truly optional
eupharis May 12, 2025
bf238b2
P3) (Optoro) Allow variable to be secret in the UI, but gettable in f…
RichardDzurus May 13, 2025
78d4b15
add generate contexts (#45)
akinboboye May 15, 2025
ebf6e6b
adds mtls and direct execute options (#44)
RichardDzurus May 22, 2025
938dfdd
polyCustom - prevent rewrites of executionId (#46)
RichardDzurus May 26, 2025
db5381b
4292 (#47)
akinboboye May 27, 2025
93cff00
create mock schemas to fit everything when using no types flag (#48)
RichardDzurus May 28, 2025
050853e
EN #4348 flatten new-lines in arg descriptions (#50)
eneumann May 28, 2025
ee50a54
EN #4360 fix return types for TS funcs (#49)
eneumann May 28, 2025
bd33593
adding ability for python client server and client functions to add c…
aarongoin May 28, 2025
bc8e096
fix type error!
aarongoin May 28, 2025
569ec60
try simple upgrade
eupharis May 30, 2025
8c9d3d1
changed version
FedeMarchiniHotovo Jun 3, 2025
bd5729d
0.3.8.dev0 make it clearer that jsonschema parsing issue is warning n…
eupharis Jun 4, 2025
19c5613
4418 p2 bug on glide pre commit hook poly prepare make sure we git ad…
Daniel-Estoll Jun 18, 2025
391871a
4523 fix python client to save generate command arguments and reuse t…
Ash1R Jun 18, 2025
0026216
Update pydantic version to work with Python 3.13 (#54)
Ash1R Jun 24, 2025
a719bc0
fix vari under no types (#56)
eupharis Jun 25, 2025
0052b8e
better import error (#59)
eupharis Jun 26, 2025
cde7993
4645 Add github action for polyapi-python unittests, fix polyapi-pyth…
Ash1R Jun 26, 2025
4672a5a
Windows glide bug (#61)
Daniel-Estoll Jun 26, 2025
aa693fe
version command in python (#58)
RichardDzurus Jun 27, 2025
c6d9b8e
P2) Webhook Payload Type Blows Up our Python Client (#62)
RichardDzurus Jun 27, 2025
d47ab1d
Fixing bug where users couldn't put a description in their polyConfig…
aarongoin Jun 27, 2025
d32781a
next
eupharis Jun 30, 2025
f8416ee
fix schema generation (#64)
RichardDzurus Jun 30, 2025
88c55a3
remove bad ci file
eupharis Jun 30, 2025
58ac792
Upgrading version to 0.3.8 (#67)
nahuel-polyapi Jul 1, 2025
7dc8423
Merge branch 'main' into develop
eupharis Jul 1, 2025
8f0e01a
4655 p3 polyapi python schema errors lets fix (#63)
Daniel-Estoll Jul 7, 2025
5bad68b
Fixed find deployables command to ensure there are no duplicates (#65)
Daniel-Estoll Jul 7, 2025
b954112
Added check for LOGS_ENABLED env var and updated exceptions (#70)
Daniel-Estoll Jul 8, 2025
3b9ea19
allow higher stdlib_list
eupharis Jul 8, 2025
f5df984
update in one more spot
eupharis Jul 8, 2025
7a7c9b4
Merge branch 'main' into develop
eupharis Jul 8, 2025
c880a6a
increase version of truststore installed
eupharis Jul 8, 2025
e59776c
added logger (#72)
Daniel-Estoll Jul 9, 2025
f4ed72e
Change print to use logging (#73)
Daniel-Estoll Jul 16, 2025
c612f6e
EN #4845 fix function args schema bug for TypedDicts
eneumann Jul 17, 2025
a584bea
Revert c612f6e (EN #4845 fix function args schema bug for TypedDicts)…
eneumann Jul 17, 2025
1575998
EN bump v to 0.3.9.dev8
eneumann Jul 17, 2025
f51658c
EN #4845 fix func arg schema bug with typed dicts (#75)
eneumann Jul 17, 2025
eb81b46
Tabi sdk (#74)
aarongoin Jul 17, 2025
afb18ff
oh lordy (#76)
aarongoin Jul 17, 2025
c15d143
One more missed f-string in tabi
aarongoin Jul 17, 2025
6d9e606
Revert monkey patch (#77)
Daniel-Estoll Jul 18, 2025
5b9f621
remove need for special logging process
eupharis Jul 21, 2025
38827b6
fix GitHub action for polyapi python unittests, fix polyapi python un…
Ash1R Jul 21, 2025
65201eb
running into weird ord bug in python3.11, lets do simpler 7 char hash…
eupharis Jul 25, 2025
e3a343b
fix tests
eupharis Jul 28, 2025
25e768a
add workflow dispatch
eupharis Jul 28, 2025
422fcc6
try under 3.13
eupharis Jul 28, 2025
d1750c6
0.3.9.dev15: define some sort of scrub_keys
eupharis Jul 28, 2025
d6b18d7
back up
eupharis Jul 28, 2025
87caa04
actually fix tests
eupharis Jul 28, 2025
8a44827
Revert "actually fix tests"
eupharis Jul 28, 2025
06e8a41
in sync with actions now?
eupharis Jul 28, 2025
989840f
update version for deploy
aarongoin Jul 31, 2025
c263e9f
Updated encoding to utf-8 (#82)
Daniel-Estoll Aug 4, 2025
a61b97f
EN #4926 fix parser to include kwargs when parsing function params (#83)
eneumann Aug 12, 2025
f40d530
EN #4926 Disallow keyword only args (#84)
eneumann Aug 14, 2025
546c839
4940 add visibility argument (#81)
Daniel-Estoll Aug 27, 2025
6471245
Implemented scrub_keys function (#85)
Daniel-Estoll Sep 3, 2025
dddf98f
fix python
eupharis Sep 3, 2025
fe0892d
Prepare for deploy
aarongoin Sep 4, 2025
7611e79
prep
aarongoin Sep 4, 2025
ebde948
EN #5300 add optional deploy env vars in setup for poly deployments (…
eneumann Sep 18, 2025
089c3c4
EN [#5300] have positional args for setup match TS
eneumann Oct 3, 2025
5e605da
EN [#5300] swap these too
eneumann Oct 3, 2025
fbdd0ae
Better uniformity with python arguments and typescript arguments, add…
aarongoin Oct 10, 2025
8bb8466
Merge branch 'main' into develop
eupharis Oct 16, 2025
3c13e77
turn it to 11!
eupharis Oct 16, 2025
0ca17da
fix test
eupharis Oct 16, 2025
c97eb1b
Removed duplicate ORs (#89)
Daniel-Estoll Dec 31, 2025
9a815ca
Masked key (#90)
Daniel-Estoll Jan 16, 2026
32782df
build latest
fede-poly Jan 27, 2026
1db455a
Merge branch 'main' into develop
eupharis Jan 27, 2026
fe01493
EN [#5917] Support async parsing; fix pyproject schema; require deplo…
eneumann Feb 9, 2026
62a859f
EN [#5917] bump to trigger py package update
eneumann Feb 10, 2026
3f43e38
callable right prefix (#95)
harshi922 Feb 17, 2026
58e7c27
EN [#5424] py: tabi: fix table runtime/type imports and table query r…
eneumann Feb 17, 2026
f015d5e
next
eupharis Feb 17, 2026
d10b960
tweak
eupharis Feb 17, 2026
d28d49e
build latest for R30
nahuel-polyapi Feb 19, 2026
df2f1ba
Merge branch 'main' into develop
eupharis Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[flake8]
ignore = E203,E303,E402,E501,E722,W391,F401,W292,F811,E302
ignore = E203,E303,E402,E501,E722,W391,F401,W292,F811,E302,W291,W293
max-line-length = 150
max-complexity = 22
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ This script is handy for checking for any mypy types:

Please ignore \[name-defined\] errors for now. This is a known bug we are working to fix!

## Strategies for QA'ing Changes To Generate Or Other Core Functionality

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).

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.

Of course all this is in addition to the changes passing through normal unittests and integration tests!

## Support

If you run into any issues or want help getting started with this project, please contact [email protected]
Expand Down
3 changes: 2 additions & 1 deletion polyapi/deployables.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import hashlib
from pathlib import Path
from typing import TypedDict, List, Dict, Tuple, Optional, Any, Union
from typing_extensions import Required
from subprocess import check_output, CalledProcessError


Expand Down Expand Up @@ -54,7 +55,7 @@ class DeployableRecord(ParsedDeployableConfig, total=False):
gitRevision: str
fileRevision: str
file: str
types: DeployableFunctionTypes
types: Required[DeployableFunctionTypes]
typeSchemas: Dict[str, Any]
dependencies: List[str]
deployments: List[Deployment]
Expand Down
16 changes: 13 additions & 3 deletions polyapi/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import types
import sys
import re
from typing import Dict, List, Mapping, Optional, Tuple, Any
from typing import Dict, List, Mapping, Optional, Tuple, Any, Union
from typing import _TypedDictMeta as BaseTypedDict # type: ignore
from typing_extensions import _TypedDictMeta, cast # type: ignore
from stdlib_list import stdlib_list
Expand Down Expand Up @@ -390,7 +390,7 @@ def visit_AnnAssign(self, node):
deployable["config"] = _parse_dict(node.value)
self._name = deployable["config"]["name"]

def _extract_docstring_from_function(self, node: ast.FunctionDef):
def _extract_docstring_from_function(self, node: Union[ast.FunctionDef, ast.AsyncFunctionDef]):
start_lineno = (node.body[0].lineno if node.body else node.lineno) - 1
start_offset = self._line_offsets[start_lineno]
end_offset = start_offset
Expand Down Expand Up @@ -452,15 +452,19 @@ def visit_Import(self, node: ast.Import):
for name in node.names:
req = _get_req_name_if_not_in_base(name.name, pip_name_lookup)
if req:
if "dependencies" not in deployable or deployable["dependencies"] is None:
deployable["dependencies"] = []
deployable["dependencies"].append(req)

def visit_ImportFrom(self, node: ast.ImportFrom):
if node.module:
req = _get_req_name_if_not_in_base(node.module, pip_name_lookup)
if req:
if "dependencies" not in deployable or deployable["dependencies"] is None:
deployable["dependencies"] = []
deployable["dependencies"].append(req)

def visit_FunctionDef(self, node: ast.FunctionDef):
def _handle_function_def(self, node: Union[ast.FunctionDef, ast.AsyncFunctionDef]):
if node.name == self._name:
# Parse docstring which may contain param types and descriptions
self._extract_docstring_from_function(node)
Expand Down Expand Up @@ -506,6 +510,12 @@ def visit_FunctionDef(self, node: ast.FunctionDef):
else:
deployable["types"]["returns"]["type"] = "Any"

def visit_FunctionDef(self, node: ast.FunctionDef):
self._handle_function_def(node)

def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef):
self._handle_function_def(node)

def generic_visit(self, node):
if hasattr(node, 'lineno') and hasattr(node, 'col_offset'):
self._current_offset = self._line_offsets[node.lineno - 1] + node.col_offset
Expand Down
150 changes: 109 additions & 41 deletions polyapi/poly_tables.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,64 @@
import os
import requests
from typing_extensions import NotRequired, TypedDict
from typing import List, Union, Type, Dict, Any, Literal, Tuple, Optional, get_args, get_origin
from typing import (
List,
Union,
Type,
Dict,
Any,
Literal,
Tuple,
Optional,
get_args,
get_origin,
)
from polyapi.utils import add_import_to_init, init_the_init
from polyapi.typedefs import TableSpecDto
from polyapi.constants import JSONSCHEMA_TO_PYTHON_TYPE_MAP
from polyapi.config import get_api_key_and_url

def scrub(data) -> Dict[str, Any]:
if (not data or not isinstance(data, (Dict, List))): return data
TABI_MODULE_IMPORTS = "\n".join(
[
"from typing_extensions import NotRequired, TypedDict",
"from typing import Union, List, Dict, Any, Literal, Optional, Required, overload",
"from polyapi.poly_tables import execute_query, first_result, transform_query, delete_one_response",
"from polyapi.typedefs import Table, PolyCountResult, PolyDeleteResult, PolyDeleteResults, SortOrder, StringFilter, NullableStringFilter, NumberFilter, NullableNumberFilter, BooleanFilter, NullableBooleanFilter, NullableObjectFilter",
]
)


def scrub(data: Any) -> Any:
if not data or not isinstance(data, (Dict, List)):
return data
if isinstance(data, List):
return [scrub(item) for item in data]
else:
temp = {}
secrets = ["x_api_key", "x-api-key", "access_token", "access-token", "authorization", "api_key", "api-key", "apikey", "accesstoken", "token", "password", "key"]
secrets = [
"x_api_key",
"x-api-key",
"access_token",
"access-token",
"authorization",
"api_key",
"api-key",
"apikey",
"accesstoken",
"token",
"password",
"key",
]
for key, value in data.items():
if isinstance(value, (Dict, List)):
temp[key] = scrub(data[key])
elif key.lower() in secrets:
temp[key] = '********'
temp[key] = "********"
else:
temp[key] = data[key]
return temp


def scrub_keys(e: Exception) -> Dict[str, Any]:
"""
Scrub the keys of an exception to remove sensitive information.
Expand All @@ -31,18 +68,26 @@ def scrub_keys(e: Exception) -> Dict[str, Any]:
"error": str(e),
"type": type(e).__name__,
"message": str(e),
"args": scrub(getattr(e, 'args', None))
"args": scrub(getattr(e, "args", None)),
}


def execute_query(table_id, method, query):
from polyapi import polyCustom
from polyapi.poly.client_id import client_id

try:
url = f"/tables/{table_id}/{method}?clientId={client_id}"
headers = {{
'x-poly-execution-id': polyCustom.get('executionId')
}}
api_key, base_url = get_api_key_and_url()
if not base_url:
raise ValueError(
"PolyAPI Instance URL is not configured, run `python -m polyapi setup`."
)

auth_key = polyCustom.get("executionApiKey") or api_key
url = f"{base_url.rstrip('/')}/tables/{table_id}/{method}?clientId={client_id}"
headers = {"x-poly-execution-id": polyCustom.get("executionId")}
if auth_key:
headers["Authorization"] = f"Bearer {auth_key}"
response = requests.post(url, json=query, headers=headers)
response.raise_for_status()
return response.json()
Expand All @@ -51,14 +96,16 @@ def execute_query(table_id, method, query):


def first_result(rsp):
if isinstance(rsp, dict) and isinstance(rsp.get('results'), list):
return rsp['results'][0] if rsp['results'] else None
if isinstance(rsp, dict) and isinstance(rsp.get("results"), list):
return rsp["results"][0] if rsp["results"] else None
return rsp


def delete_one_response(rsp):
if isinstance(rsp, dict) and isinstance(rsp.get('deleted'), int):
return { 'deleted': bool(rsp.get('deleted')) }
return { 'deleted': false }
if isinstance(rsp, dict) and isinstance(rsp.get("deleted"), int):
return {"deleted": bool(rsp.get("deleted"))}
return {"deleted": False}


_key_transform_map = {
"not_": "not",
Expand All @@ -72,8 +119,7 @@ def delete_one_response(rsp):
def _transform_keys(obj: Any) -> Any:
if isinstance(obj, dict):
return {
_key_transform_map.get(k, k): _transform_keys(v)
for k, v in obj.items()
_key_transform_map.get(k, k): _transform_keys(v) for k, v in obj.items()
}

elif isinstance(obj, list):
Expand All @@ -88,13 +134,13 @@ def transform_query(query: dict) -> dict:
return {
**query,
"where": _transform_keys(query["where"]) if query["where"] else None,
"orderBy": query["order_by"] if query["order_by"] else None
"orderBy": query["order_by"] if query["order_by"] else None,
}

return query


TABI_TABLE_TEMPLATE = '''
TABI_TABLE_TEMPLATE = """
{table_name}Columns = Literal[{table_columns}]


Expand Down Expand Up @@ -369,19 +415,25 @@ def delete_one(*args, **kwargs) -> PolyDeleteResult:
query["where"]["id"] = kwargs["id"]
query.pop("id", None)
return delete_one_response(execute_query({table_name}.table_id, "delete", transform_query(query)))
'''
"""


def _get_column_type_str(name: str, schema: Dict[str, Any], is_required: bool) -> str:
result = ""

col_type = schema.get("type", "object")
if isinstance(col_type, list):
subtypes = [_get_column_type_str(name, { **schema, "type": t }, is_required) for t in col_type]
subtypes = [
_get_column_type_str(name, {**schema, "type": t}, is_required)
for t in col_type
]
result = f"Union[{', '.join(subtypes)}]"
elif col_type == "array":
if isinstance(schema["items"], list):
subtypes = [_get_column_type_str(f"{name}{i}", s, True) for i, s in enumerate(schema["items"])]
subtypes = [
_get_column_type_str(f"{name}{i}", s, True)
for i, s in enumerate(schema["items"])
]
result = f"Tuple[{', '.join(subtypes)}]"
elif isinstance(schema["items"], dict):
result = f"List[{_get_column_type_str(name, schema['items'], True)}]"
Expand All @@ -391,7 +443,10 @@ def _get_column_type_str(name: str, schema: Dict[str, Any], is_required: bool) -
if isinstance(schema.get("patternProperties"), dict):
# TODO: Handle multiple pattern properties
result = f"Dict[str, {_get_column_type_str(f'{name}_', schema['patternProperties'], True)}]"
elif isinstance(schema.get("properties"), dict) and len(schema["properties"].values()) > 0:
elif (
isinstance(schema.get("properties"), dict)
and len(schema["properties"].values()) > 0
):
# TODO: Handle x-poly-refs
result = f'"{name}"'
else:
Expand All @@ -413,24 +468,32 @@ def _render_table_row_classes(table_name: str, schema: Dict[str, Any]) -> str:
return output[1].split("\n", 1)[1].strip()


def _render_table_subset_class(table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]) -> str:
def _render_table_subset_class(
table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]
) -> str:
# Generate class which can match any subset of a table row
lines = [f"class {table_name}Subset(TypedDict):"]

for name, schema in columns:
type_str = _get_column_type_str(f"_{table_name}Row{name}", schema, name in required)
type_str = _get_column_type_str(
f"_{table_name}Row{name}", schema, name in required
)
lines.append(f" {name}: NotRequired[{type_str}]")

return "\n".join(lines)


def _render_table_where_class(table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]) -> str:
def _render_table_where_class(
table_name: str, columns: List[Tuple[str, Dict[str, Any]]], required: List[str]
) -> str:
# Generate class for the 'where' part of the query
lines = [f"class {table_name}WhereFilter(TypedDict):"]

for name, schema in columns:
ftype_str = ""
type_str = _get_column_type_str(f"_{table_name}Row{name}", schema, True) # force required to avoid wrapping type in Optional[]
type_str = _get_column_type_str(
f"_{table_name}Row{name}", schema, True
) # force required to avoid wrapping type in Optional[]
is_required = name in required
if type_str == "bool":
ftype_str = "BooleanFilter" if is_required else "NullableBooleanFilter"
Expand All @@ -445,24 +508,34 @@ def _render_table_where_class(table_name: str, columns: List[Tuple[str, Dict[str
if ftype_str:
lines.append(f" {name}: NotRequired[Union[{type_str}, {ftype_str}]]")

lines.append(f' AND: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]')
lines.append(
f' AND: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]'
)
lines.append(f' OR: NotRequired[List["{table_name}WhereFilter"]]')
lines.append(f' NOT: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]')
lines.append(
f' NOT: NotRequired[Union["{table_name}WhereFilter", List["{table_name}WhereFilter"]]]'
)

return "\n".join(lines)


def _render_table(table: TableSpecDto) -> str:
columns = list(table["schema"]["properties"].items())
required_colunms = table["schema"].get("required", [])
required_columns = table["schema"].get("required", [])

table_columns = ",".join([ f'"{k}"' for k,_ in columns])
table_columns = ",".join([f'"{k}"' for k, _ in columns])
table_row_classes = _render_table_row_classes(table["name"], table["schema"])
table_row_subset_class = _render_table_subset_class(table["name"], columns, required_colunms)
table_where_class = _render_table_where_class(table["name"], columns, required_colunms)
table_row_subset_class = _render_table_subset_class(
table["name"], columns, required_columns
)
table_where_class = _render_table_where_class(
table["name"], columns, required_columns
)
if table.get("description", ""):
table_description = '\n """'
table_description += '\n '.join(table["description"].replace('"', "'").split("\n"))
table_description = '\n """'
table_description += "\n ".join(
table["description"].replace('"', "'").split("\n")
)
table_description += '\n """'
else:
table_description = ""
Expand Down Expand Up @@ -502,12 +575,7 @@ def _create_table(table: TableSpecDto) -> None:

init_path = os.path.join(full_path, "__init__.py")

imports = "\n".join([
"from typing_extensions import NotRequired, TypedDict",
"from typing import Union, List, Dict, Any, Literal, Optional, Required, overload",
"from polyapi.poly_tables import execute_query, first_result, transform_query",
"from polyapi.typedefs import Table, PolyCountResult, PolyDeleteResults, SortOrder, StringFilter, NullableStringFilter, NumberFilter, NullableNumberFilter, BooleanFilter, NullableBooleanFilter, NullableObjectFilter",
])
imports = TABI_MODULE_IMPORTS
table_contents = _render_table(table)

file_contents = ""
Expand Down
Loading