Skip to content

Commit

Permalink
Add python api_resource template
Browse files Browse the repository at this point in the history
  • Loading branch information
svix-mman committed Jan 16, 2025
1 parent ad04cc4 commit 72e0612
Showing 1 changed file with 124 additions and 0 deletions.
124 changes: 124 additions & 0 deletions templates/svix-lib-python/api_resource.py.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{% set api_mod_name %}{{ resource.name | to_snake_case }}_api{% endset -%}
{% set resource_class_name = resource.name | to_upper_camel_case -%}
{% set resource_type_name = resource.name | to_upper_camel_case -%}

import typing as t
from datetime import datetime
from dataclasses import dataclass,asdict

from deprecated import deprecated
from .common import PostOptions, ApiBase, BaseOptions
from ..internal.openapi_client.client import AuthenticatedClient
from ..internal.openapi_client import models

{% if resource.operations | length > 0 %}

from ..internal.openapi_client.api.{{ resource.name | to_snake_case }} import (
{% for op in resource.operations %}
{{ op.id | to_snake_case }},
{%- endfor %}
)
{% for op in resource.operations -%}
{#-
FIXME: this is a hack. i want to be able to export the resource types from this file so i have to import them (not just use models.Resource)
But this will result in duplicate import statements. ruff check --fix will remove them, but ideally we find a better way to do this
-#}
{%- if op.request_body_schema_name is defined %}
from ..internal.openapi_client.models.{{ op.request_body_schema_name | to_snake_case }} import {{ op.request_body_schema_name | to_upper_camel_case }}
{%- endif -%}
{%- if op.response_body_schema_name is defined %}
from ..internal.openapi_client.models.{{ op.response_body_schema_name | to_snake_case }} import {{ op.response_body_schema_name | to_upper_camel_case }}
{%- endif -%}
{% endfor %}
{% endif %}


{# FIXME: need to understand how this template generates newlines and stop generating newlines #}
{% for op in resource.operations %}
{% if op.query_params | length > 0 or op.header_params | length > 0 %}
@dataclass
class {{ resource_type_name }}{{ op.name | to_upper_camel_case }}Options(BaseOptions):
{%- for p in op.query_params %}
{%- if p.description is defined %}
# {{ p.description }}
{%- endif %}
{%- if p.required %}
{{ p.name }}: {{ p.type.to_python() }}
{%- else %}
{{ p.name }}: t.Optional[{{ p.type.to_python() }}] = None
{%- endif %}
{%- endfor %}
{# FIXME: hardcoding idempotency-key for now since that is the only header param #}
{%- if op.header_params | length > 0 %}
idempotency_key: t.Optional[str] = None
{%- endif %}
{%- endif %}
{%- endfor %}


{%- for is_async in [true, false] %}
class {{ resource.name | to_upper_camel_case }}{% if is_async %}Async{% endif %}(ApiBase):
{%- if resource.operations | length != 0 %}
{%- for op in resource.operations %}
{# FIXME: find a better way to deal with python's reserved keywords!, for now i do this hack #}
{%- if op.name == "import" %}
{%- set op_name = "import_" %}
{%- else %}
{%- set op_name = op.name | to_snake_case %}
{%- endif %}
{% if op.deprecated %}
@deprecated
{%- endif %}
{%- if is_async -%}
{%- set func_def = "async def" %}
{%- else %}
{%- set func_def = "def" %}
{%- endif %}
{{ func_def }} {{ op_name }}(self
{#- path parameters are non optional strings #}
{% for p in op.path_params -%}
,{{ p }}: str
{% endfor -%}
{# body parameter struct #}
{%- if op.request_body_schema_name is defined %}
,{{ op.request_body_schema_name | to_snake_case }}: {{ op.request_body_schema_name }}
{%- endif %}

{# add query_options type #}
{%- if op.query_params | length > 0 or op.header_params | length > 0 %}
,options: {{ resource_type_name }}{{ op.name | to_upper_camel_case }}Options = {{ resource_type_name }}{{ op.name | to_upper_camel_case }}Options()
{%- endif %}

) ->
{%- if op.response_body_schema_name is defined -%}
{{ op.response_body_schema_name | to_upper_camel_case }}:
{% else -%}
None:
{%- endif %}
{% if op.description is defined -%}
{{ op.description | to_doc_comment(style="python") }}
{%- endif -%}
{%- set internal_func_name -%}
{{ op.id | to_snake_case }}{% if is_async -%}.request_asyncio{% else -%}.request_sync{% endif -%}
{%- endset -%}
{% set ret -%}
{%- if is_async -%}return await{% else %}return{% endif -%}
{%- endset %}
{{ ret }} {{ internal_func_name }}(client=self._client
{%- for p in op.path_params -%}
,{{ p }}={{ p }}
{%- endfor -%}
{% if op.request_body_schema_name is defined -%}
,json_body={{ op.request_body_schema_name | to_snake_case }}
{% endif -%}
{% if (op.query_params | length > 0 )or (op.header_params | length > 0) %}
{# FIXME: how do we know there is no duplicate options in the path params #}
,**options.to_dict()
{% endif -%}
)
{% endfor -%}
{% else %}
{# empty class with no functions, so we have a pass here #}
pass
{% endif %}
{% endfor %}

0 comments on commit 72e0612

Please sign in to comment.