mirror of
https://github.com/kennethreitz/neon-api-python.git
synced 2026-06-05 22:50:18 +00:00
Add Neon API package and related files
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
from .client import NeonAPI
|
||||
from .__version__ import __version__
|
||||
from .exceptions import NeonAPIError
|
||||
|
||||
|
||||
def from_environ():
|
||||
"""Create a NeonAPI instance from environment variables."""
|
||||
|
||||
return NeonAPI.from_environ()
|
||||
|
||||
|
||||
def from_token(token):
|
||||
"""Create a NeonAPI instance from a token."""
|
||||
|
||||
return NeonAPI.from_token(token)
|
||||
@@ -0,0 +1 @@
|
||||
__version__ = "0.1.0"
|
||||
@@ -0,0 +1,809 @@
|
||||
import os
|
||||
import typing as t
|
||||
from datetime import datetime
|
||||
from functools import wraps
|
||||
|
||||
import requests
|
||||
|
||||
from . import schema
|
||||
from .utils import compact_mapping, to_iso8601
|
||||
from .exceptions import NeonAPIError
|
||||
|
||||
|
||||
__VERSION__ = "0.1.0"
|
||||
|
||||
NEON_API_KEY_ENVIRON = "NEON_API_KEY"
|
||||
NEON_API_BASE_URL = "https://console.neon.tech/api/v2/"
|
||||
ENABLE_PYDANTIC = True
|
||||
|
||||
|
||||
def returns_model(model, is_array=False):
|
||||
"""Decorator that returns a Pydantic dataclass.
|
||||
|
||||
:param model: The Pydantic dataclass to return.
|
||||
:param is_array: Whether the return value is an array (default is False).
|
||||
:return: A Pydantic dataclass.
|
||||
|
||||
If Pydantic is not enabled, the original return value is returned.
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not ENABLE_PYDANTIC:
|
||||
return func(*args, **kwargs)
|
||||
|
||||
if is_array:
|
||||
return [model(**item) for item in func(*args, **kwargs)]
|
||||
else:
|
||||
return model(**func(*args, **kwargs))
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def returns_subkey(key):
|
||||
"""Decorator that returns a subkey.
|
||||
|
||||
:param key: The key to return.
|
||||
:return: The value of the key in the return value.
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return getattr(func(*args, **kwargs), key)
|
||||
except AttributeError:
|
||||
return func(*args, **kwargs)[key]
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
class NeonAPI:
|
||||
def __init__(self, api_key: str, *, base_url: str = None):
|
||||
"""A Neon API client.
|
||||
|
||||
:param api_key: The API key to use for authentication.
|
||||
:param base_url: The base URL of the Neon API (default is https://console.neon.tech/api/v2/).
|
||||
"""
|
||||
|
||||
# Set the base URL.
|
||||
if not base_url:
|
||||
base_url = NEON_API_BASE_URL
|
||||
|
||||
# Private attributes.
|
||||
self._api_key = api_key
|
||||
self._session = requests.Session()
|
||||
|
||||
# Public attributes.
|
||||
self.base_url = base_url
|
||||
self.user_agent = f"neon-client/python version=({__VERSION__})"
|
||||
|
||||
def __repr__(self):
|
||||
return f"<NeonAPI base_url={self.base_url!r}>"
|
||||
|
||||
def _request(
|
||||
self,
|
||||
method: str,
|
||||
path: str,
|
||||
**kwargs,
|
||||
):
|
||||
"""Send an HTTP request to the specified API path using the specified method.
|
||||
|
||||
:param method: The HTTP method to use (e.g., "GET", "POST", "PUT", "DELETE").
|
||||
:param path: The API path to send the request to.
|
||||
:param kwargs: Additional keyword arguments to pass to the requests.Session.request method.
|
||||
:return: The JSON response from the server.
|
||||
"""
|
||||
|
||||
# Set HTTP headers for outgoing requests.
|
||||
headers = kwargs.pop("headers", {})
|
||||
headers["Authorization"] = f"Bearer {self._api_key}"
|
||||
headers["Accept"] = "application/json"
|
||||
headers["Content-Type"] = "application/json"
|
||||
headers["User-Agent"] = self.user_agent
|
||||
|
||||
# Send the request.
|
||||
r = self._session.request(
|
||||
method, self.base_url + path, headers=headers, **kwargs
|
||||
)
|
||||
|
||||
# Check the response status code.
|
||||
try:
|
||||
r.raise_for_status()
|
||||
except requests.exceptions.HTTPError:
|
||||
raise NeonAPIError(r.text)
|
||||
|
||||
return r.json()
|
||||
|
||||
def _url_join(self, *args):
|
||||
"""Join a list of URL components into a single URL."""
|
||||
|
||||
return "/".join(args)
|
||||
|
||||
@classmethod
|
||||
def from_environ(cls):
|
||||
"""Create a new Neon API client from the `NEON_API_KEY` environment variable."""
|
||||
|
||||
return cls(os.environ[NEON_API_KEY_ENVIRON])
|
||||
|
||||
@returns_model(schema.CurrentUserInfoResponse)
|
||||
def me(self) -> t.Dict[str, t.Any]:
|
||||
"""Get the current user.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getcurrentuserinfo
|
||||
"""
|
||||
|
||||
return self._request("GET", "users/me")
|
||||
|
||||
@returns_model(schema.ApiKeysListResponseItem, is_array=True)
|
||||
def api_keys(self) -> t.List[t.Dict[str, t.Any]]:
|
||||
"""Get a list of API keys.
|
||||
|
||||
:return: A dataclass representing the API key.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listapikeys
|
||||
"""
|
||||
|
||||
return self._request("GET", "api_keys")
|
||||
|
||||
@returns_model(schema.ApiKeyCreateResponse)
|
||||
def api_key_create(self, **json: dict) -> t.Dict[str, t.Any]:
|
||||
"""Create a new API key.
|
||||
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the API key.
|
||||
|
||||
Example usage:
|
||||
|
||||
>>> neon.api_key_create(name="My API Key")
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/createapikey
|
||||
"""
|
||||
|
||||
return self._request("POST", "api_keys", json=json)
|
||||
|
||||
@returns_model(schema.ApiKeyRevokeResponse)
|
||||
def api_key_revoke(self, api_key_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Revoke an API key.
|
||||
|
||||
:param api_key_id: The ID of the API key to revoke.
|
||||
:return: A dataclass representing the API key.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/revokeapikey
|
||||
"""
|
||||
return self._request("DELETE", f"api_keys/{ api_key_id }")
|
||||
|
||||
@returns_model(schema.ProjectsResponse)
|
||||
def projects(
|
||||
self,
|
||||
*,
|
||||
shared: bool = False,
|
||||
cursor: str | None = None,
|
||||
limit: int | None = None,
|
||||
) -> t.List[t.Dict[str, t.Any]]:
|
||||
"""Get a list of projects. If shared is True, get a list of shared projects.
|
||||
|
||||
:param shared: Whether to retrieve shared projects (default is False).
|
||||
:param cursor: The cursor for pagination (default is None).
|
||||
:param limit: The maximum number of projects to retrieve (default is None).
|
||||
:return: A list of dataclasses representing the projects.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojects
|
||||
"""
|
||||
|
||||
r_path = "projects" if not shared else "projects/shared"
|
||||
r_params = compact_mapping({"cursor": cursor, "limit": limit})
|
||||
|
||||
return self._request("GET", r_path, params=r_params)
|
||||
|
||||
@returns_model(schema.ProjectResponse)
|
||||
def project(self, project_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Get a project.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:return: A dataclass representing the project.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getproject
|
||||
"""
|
||||
|
||||
r_path = f"projects/{project_id}"
|
||||
|
||||
return self._request("GET", r_path)
|
||||
|
||||
@returns_model(schema.ProjectResponse)
|
||||
def project_create(self, **json: dict) -> t.Dict[str, t.Any]:
|
||||
"""Create a new project. Accepts all keyword arguments for json body.
|
||||
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the project.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/createproject
|
||||
"""
|
||||
|
||||
return self._request("POST", "projects", json=json)
|
||||
|
||||
@returns_model(schema.ProjectResponse)
|
||||
def project_update(self, project_id: str, **json: dict) -> t.Dict[str, t.Any]:
|
||||
"""Updates a project. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the project.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/updateproject"""
|
||||
|
||||
return self._request("PATCH", f"projects/{ project_id }", json=json)
|
||||
|
||||
@returns_model(schema.ProjectResponse)
|
||||
def project_delete(self, project_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Delete a project.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:return: A dataclass representing the project.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/deleteproject
|
||||
"""
|
||||
|
||||
return self._request("DELETE", f"projects/{ project_id }")
|
||||
|
||||
@returns_model(schema.ProjectPermissions)
|
||||
def project_permissions(self, project_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Get a project permissions.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:return: A dataclass representing the project permissions.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojectpermissions
|
||||
"""
|
||||
return self._request("GET", f"projects/{ project_id }/permissions")
|
||||
|
||||
@returns_model(schema.ProjectPermission)
|
||||
def project_permissions_grant(
|
||||
self, project_id: str, **json: dict
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Update a project permissions. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the project permissions.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/grantpermissiontoproject
|
||||
"""
|
||||
return self._request("POST", f"projects/{ project_id }/permissions", json=json)
|
||||
|
||||
@returns_model(schema.ProjectPermission)
|
||||
def project_permissions_revoke(
|
||||
self, project_id: str, **json: dict
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Update a project permissions. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the project permissions.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/revokepermissionfromproject
|
||||
"""
|
||||
return self._request(
|
||||
"DELETE", f"projects/{ project_id }/permissions", json=json
|
||||
)
|
||||
|
||||
@returns_model(schema.BranchesResponse)
|
||||
def branches(
|
||||
self,
|
||||
project_id: str,
|
||||
*,
|
||||
cursor: str | None = None,
|
||||
limit: int | None = None,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Get a list of branches.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param cursor: The cursor for pagination (default is None).
|
||||
:param limit: The maximum number of projects to retrieve (default is None).
|
||||
:return: A list of dataclasses representing the projects.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojectbranches
|
||||
"""
|
||||
|
||||
# Construct the request path and parameters.
|
||||
r_path = self._url_join("projects", project_id, "branches")
|
||||
r_params = compact_mapping({"cursor": cursor, "limit": limit})
|
||||
|
||||
# Make the request.
|
||||
return self._request("GET", r_path, params=r_params)
|
||||
|
||||
@returns_model(schema.BranchResponse)
|
||||
def branch(self, project_id: str, branch_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Get a branch.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:return: A dataclass representing the branch.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getprojectbranch
|
||||
"""
|
||||
|
||||
# Construct the request path.
|
||||
r_path = self._url_join("projects", project_id, "branches", branch_id)
|
||||
|
||||
# Make the request.
|
||||
return self._request("GET", r_path)
|
||||
|
||||
@returns_model(schema.BranchOperations)
|
||||
def branch_create(self, project_id: str, **json: dict) -> t.Dict[str, t.Any]:
|
||||
"""Create a new branch. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the branch.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/createprojectbranch
|
||||
"""
|
||||
return self._request("POST", f"projects/{ project_id }/branches", json=json)
|
||||
|
||||
@returns_model(schema.BranchOperations)
|
||||
def branch_update(
|
||||
self, project_id: str, branch_id: str, **json: dict
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Update a branch by branch_id. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the branch.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/updateprojectbranch
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"PATCH", f"projects/{ project_id }/branches/{ branch_id }", json=json
|
||||
)
|
||||
|
||||
@returns_model(schema.BranchOperations)
|
||||
def branch_delete(self, project_id: str, branch_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Delete a branch by branch_id.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:return: A dataclass representing the branch.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/deleteprojectbranch
|
||||
"""
|
||||
return self._request(
|
||||
"DELETE", f"projects/{ project_id }/branches/{ branch_id }"
|
||||
)
|
||||
|
||||
@returns_model(schema.BranchOperations)
|
||||
def branch_set_as_primary(
|
||||
self, project_id: str, branch_id: str
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Set a branch as primary by branch_id.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:return: A dataclass representing the branch.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/setprimaryprojectbranch"""
|
||||
|
||||
return self._request(
|
||||
"POST", f"projects/{ project_id }/branches/{ branch_id }/set_as_primary"
|
||||
)
|
||||
|
||||
@returns_model(schema.DatabasesResponse)
|
||||
def databases(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
*,
|
||||
cursor: str | None = None,
|
||||
limit: int | None = None,
|
||||
) -> t.List[t.Dict[str, t.Any]]:
|
||||
"""Get a list of databases.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param cursor: The cursor for pagination (default is None).
|
||||
:param limit: The maximum number of projects to retrieve (default is None).
|
||||
:return: A list of dataclasses representing the database.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojectbranchdatabases
|
||||
"""
|
||||
|
||||
# Construct the request path and parameters.
|
||||
r_path = self._url_join(
|
||||
"projects", project_id, "branches", branch_id, "databases"
|
||||
)
|
||||
r_params = compact_mapping({"cursor": cursor, "limit": limit})
|
||||
|
||||
# Make the request.
|
||||
return self._request("GET", r_path, params=r_params)
|
||||
|
||||
@returns_model(schema.DatabaseResponse)
|
||||
def database(
|
||||
self, project_id: str, branch_id: str, database_id: str
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Get a database.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param database_id: The ID of the database.
|
||||
:return: A dataclass representing the database.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getprojectbranchdatabase
|
||||
"""
|
||||
|
||||
# Construct the request path.
|
||||
r_path = self._url_join(
|
||||
"projects", project_id, "branches", branch_id, "databases", database_id
|
||||
)
|
||||
|
||||
# Make the request.
|
||||
return self._request("GET", r_path)
|
||||
|
||||
@returns_model(schema.DatabaseResponse)
|
||||
def database_create(
|
||||
self, project_id: str, branch_id: str, **json: dict
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Create a new database. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the database.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/createprojectbranchdatabase
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"POST",
|
||||
f"projects/{ project_id }/branches/{ branch_id }/databases",
|
||||
json=json,
|
||||
)
|
||||
|
||||
@returns_model(schema.DatabaseResponse)
|
||||
def database_update(
|
||||
self, project_id: str, branch_id: str, database_id: str, **json: dict
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Update a database. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param database_id: The ID of the database.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the database.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/updateprojectbranchdatabase
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"PUT",
|
||||
f"projects/{ project_id }/branches/{ branch_id }/databases/{ database_id }",
|
||||
json=json,
|
||||
)
|
||||
|
||||
@returns_model(schema.DatabaseResponse)
|
||||
def database_delete(
|
||||
self, project_id: str, branch_id: str, database_id: str
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Delete a database by database_id.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param database_id: The ID of the database.
|
||||
:return: A dataclass representing the database.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/deleteprojectbranchdatabase
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"DELETE",
|
||||
f"projects/{ project_id }/branches/{ branch_id }/databases/{ database_id }",
|
||||
)
|
||||
|
||||
@returns_model(schema.EndpointsResponse)
|
||||
def endpoints(self, project_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Get a list of endpoints for a given branch
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:return: A list of dataclasses representing the endpoints.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojectendpoints
|
||||
"""
|
||||
return self._request("GET", f"projects/{ project_id }/endpoints")
|
||||
|
||||
@returns_model(schema.EndpointResponse)
|
||||
def endpoint(self, project_id: str, endpoint_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Get an endpoint for a given branch.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param endpoint_id: The ID of the endpoint.
|
||||
:return: A dataclass representing the endpoint.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getprojectendpoint
|
||||
"""
|
||||
return self._request(
|
||||
"GET",
|
||||
f"projects/{ project_id }/endpoints/{ endpoint_id }",
|
||||
)
|
||||
|
||||
@returns_model(schema.EndpointOperations)
|
||||
def endpoint_create(
|
||||
self,
|
||||
project_id: str,
|
||||
**json: dict,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Create a new endpoint. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the endpoint.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/createprojectendpoint
|
||||
"""
|
||||
|
||||
return self._request("POST", f"projects/{ project_id }/endpoints", json=json)
|
||||
|
||||
@returns_model(schema.EndpointOperations)
|
||||
def endpoint_delete(self, project_id: str, endpoint_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Delete an endpoint by endpoint_id.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param endpoint_id: The ID of the endpoint.
|
||||
:return: A dataclass representing the endpoint.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/deleteprojectendpoint
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"DELETE",
|
||||
f"projects/{ project_id }/endpoints/{ endpoint_id }",
|
||||
)
|
||||
|
||||
@returns_model(schema.EndpointOperations)
|
||||
def endpoint_update(
|
||||
self, project_id: str, endpoint_id: str, **json: dict
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Update an endpoint. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param endpoint_id: The ID of the endpoint.
|
||||
:param json: The JSON paypload to send to the server.
|
||||
:return: A dataclass representing the endpoint.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/updateprojectendpoint
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"PATCH",
|
||||
f"projects/{ project_id }/endpoints/{ endpoint_id }",
|
||||
json=json,
|
||||
)
|
||||
|
||||
@returns_model(schema.EndpointOperations)
|
||||
def endpoint_start(self, project_id: str, endpoint_id: str):
|
||||
"""Start an endpoint by endpoint_id.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param endpoint_id: The ID of the endpoint.
|
||||
:return: A dataclass representing the endpoint.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/startprojectendpoint"""
|
||||
|
||||
return self._request(
|
||||
"POST",
|
||||
f"projects/{ project_id }/endpoints/{ endpoint_id }/start",
|
||||
)
|
||||
|
||||
@returns_model(schema.EndpointOperations)
|
||||
def endpoint_suspend(self, project_id: str, endpoint_id: str):
|
||||
"""Suspend an endpoint by endpoint_id.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param endpoint_id: The ID of the endpoint.
|
||||
:return: A dataclass representing the endpoint.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/suspendprojectendpoint
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"POST",
|
||||
f"projects/{ project_id }/endpoints/{ endpoint_id }/suspend",
|
||||
)
|
||||
|
||||
@returns_model(schema.RolesResponse)
|
||||
def roles(self, project_id: str, branch_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Get a list of roles for a given branch.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:return: A list of dataclasses representing the roles.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojectbranchroles
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"GET", f"projects/{ project_id }/branches/{ branch_id }/roles"
|
||||
)
|
||||
|
||||
@returns_model(schema.RoleResponse)
|
||||
def role(
|
||||
self, project_id: str, branch_id: str, role_name: str
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Get a role for a given branch.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param role_name: The name of the role.
|
||||
:return: A dataclass representing the role.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getprojectbranchrole
|
||||
|
||||
"""
|
||||
return self._request(
|
||||
"GET", f"projects/{ project_id }/branches/{ branch_id }/roles/{ role_name }"
|
||||
)
|
||||
|
||||
@returns_model(schema.RoleOperations)
|
||||
def role_create(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
role_name: str,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Create a new role. Accepts all keyword arguments for json body.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param role_name: The name of the role.
|
||||
:return: A dataclass representing the role.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/createprojectbranchrole
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"POST",
|
||||
f"projects/{ project_id }/branches/{ branch_id }/roles",
|
||||
json={"role": {"name": role_name}},
|
||||
)
|
||||
|
||||
@returns_model(schema.RoleOperations)
|
||||
def role_delete(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
role_name: str,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Delete a role by given role name.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param role_name: The name of the role.
|
||||
:return: A dataclass representing the role.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/deleteprojectbranchrole
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"DELETE",
|
||||
f"projects/{ project_id }/branches/{ branch_id }/roles/{ role_name }",
|
||||
)
|
||||
|
||||
@returns_model(schema.RolePasswordResponse)
|
||||
def role_password_reveal(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
role_name: str,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Get a role password.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param role_name: The name of the role.
|
||||
:return: A dataclass representing the role password.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getprojectbranchrolepassword"""
|
||||
|
||||
return self._request(
|
||||
"POST",
|
||||
f"projects/{ project_id }/branches/{ branch_id }/roles/{ role_name }/reveal_password",
|
||||
)
|
||||
|
||||
@returns_model(schema.RoleOperations)
|
||||
def role_password_reset(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
role_name: str,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Reset a role password.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param branch_id: The ID of the branch.
|
||||
:param role_name: The name of the role.
|
||||
:return: A dataclass representing the role.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/resetprojectbranchrolepassword
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"POST",
|
||||
f"projects/{ project_id }/branches/{ branch_id }/roles/{ role_name }/reset_password",
|
||||
)
|
||||
|
||||
@returns_model(schema.OperationsResponse)
|
||||
def operations(
|
||||
self,
|
||||
project_id: str,
|
||||
*,
|
||||
cursor: str | None = None,
|
||||
limit: int | None = None,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Get a list of operations.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param cursor: The cursor for pagination (default is None).
|
||||
:param limit: The maximum number of projects to retrieve (default is None).
|
||||
:return: A list of dataclasses representing the operations.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojectoperations
|
||||
"""
|
||||
|
||||
r_params = compact_mapping({"cursor": cursor, "limit": limit})
|
||||
return self._request(
|
||||
"GET", f"projects/{ project_id }/operations", params=r_params
|
||||
)
|
||||
|
||||
@returns_model(schema.OperationResponse)
|
||||
def operation(self, project_id: str, operation_id: str) -> t.Dict[str, t.Any]:
|
||||
"""Get an operation.
|
||||
|
||||
:param project_id: The ID of the project.
|
||||
:param operation_id: The ID of the operation.
|
||||
:return: A dataclass representing the operation.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/getprojectoperation
|
||||
"""
|
||||
|
||||
return self._request(
|
||||
"GET", f"projects/{ project_id }/operations/{ operation_id }"
|
||||
)
|
||||
|
||||
@returns_model(schema.ProjectsConsumptionResponse)
|
||||
def consumption(
|
||||
self,
|
||||
*,
|
||||
cursor: str | None = None,
|
||||
limit: int | None = None,
|
||||
from_date: datetime | str | None = None,
|
||||
to_date: datetime | str | None = None,
|
||||
) -> t.Dict[str, t.Any]:
|
||||
"""Experimental — get a list of consumption metrics for all projects.
|
||||
|
||||
:param cursor: The cursor for pagination (default is None).
|
||||
:param limit: The maximum number of projects to retrieve (default is None).
|
||||
:param from_date: The start date for the consumption metrics (default is None).
|
||||
:param to_date: The end date for the consumption metrics (default is None).
|
||||
:return: A dataclass representing the consumption metrics.
|
||||
|
||||
More info: https://api-docs.neon.tech/reference/listprojectsconsumption
|
||||
"""
|
||||
|
||||
# Convert datetime objects to ISO 8601 strings.
|
||||
from_date = (
|
||||
to_iso8601(from_date) if isinstance(from_date, datetime) else from_date
|
||||
)
|
||||
to_date = to_iso8601(to_date) if isinstance(to_date, datetime) else to_date
|
||||
|
||||
# Construct the request parameters.
|
||||
r_params = compact_mapping(
|
||||
{"cursor": cursor, "limit": limit, "from": from_date, "to": to_date}
|
||||
)
|
||||
|
||||
# Make the request.
|
||||
return self._request("GET", "consumption/projects", params=r_params)
|
||||
@@ -0,0 +1,5 @@
|
||||
from requests.exceptions import HTTPError
|
||||
|
||||
|
||||
class NeonAPIError(HTTPError):
|
||||
pass
|
||||
@@ -0,0 +1,763 @@
|
||||
# generated by datamodel-codegen:
|
||||
# filename: v2.json
|
||||
# timestamp: 2024-01-31T14:58:13+00:00
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
|
||||
class Provisioner(Enum):
|
||||
k8s_pod = "k8s-pod"
|
||||
k8s_neonvm = "k8s-neonvm"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Pagination:
|
||||
cursor: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class EmptyResponse:
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApiKeyCreateRequest:
|
||||
key_name: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApiKeyCreateResponse:
|
||||
id: int
|
||||
key: str
|
||||
name: str
|
||||
created_at: datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApiKeyRevokeResponse:
|
||||
id: int
|
||||
name: str
|
||||
revoked: bool
|
||||
last_used_from_addr: str
|
||||
last_used_at: Optional[datetime] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApiKeysListResponseItem:
|
||||
id: int
|
||||
name: str
|
||||
created_at: datetime
|
||||
last_used_from_addr: str
|
||||
last_used_at: Optional[datetime] = None
|
||||
|
||||
|
||||
class OperationAction(Enum):
|
||||
create_compute = "create_compute"
|
||||
create_timeline = "create_timeline"
|
||||
start_compute = "start_compute"
|
||||
suspend_compute = "suspend_compute"
|
||||
apply_config = "apply_config"
|
||||
check_availability = "check_availability"
|
||||
delete_timeline = "delete_timeline"
|
||||
create_branch = "create_branch"
|
||||
tenant_ignore = "tenant_ignore"
|
||||
tenant_attach = "tenant_attach"
|
||||
tenant_detach = "tenant_detach"
|
||||
tenant_reattach = "tenant_reattach"
|
||||
replace_safekeeper = "replace_safekeeper"
|
||||
disable_maintenance = "disable_maintenance"
|
||||
apply_storage_config = "apply_storage_config"
|
||||
|
||||
|
||||
class OperationStatus(Enum):
|
||||
running = "running"
|
||||
finished = "finished"
|
||||
failed = "failed"
|
||||
scheduling = "scheduling"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Branch:
|
||||
name: Optional[str] = None
|
||||
role_name: Optional[str] = None
|
||||
database_name: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectPermission:
|
||||
id: str
|
||||
granted_to_email: str
|
||||
granted_at: datetime
|
||||
revoked_at: Optional[datetime] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectPermissions:
|
||||
project_permissions: list[ProjectPermission]
|
||||
|
||||
|
||||
@dataclass
|
||||
class GrantPermissionToProjectRequest:
|
||||
email: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectConsumption:
|
||||
project_id: str
|
||||
period_id: str
|
||||
data_storage_bytes_hour: int
|
||||
synthetic_storage_size: int
|
||||
data_transfer_bytes: int
|
||||
written_data_bytes: int
|
||||
compute_time_seconds: int
|
||||
active_time_seconds: int
|
||||
updated_at: Optional[datetime]
|
||||
period_start: Optional[datetime]
|
||||
period_end: Optional[datetime]
|
||||
previous_period_id: Optional[str]
|
||||
data_storage_bytes_hour_updated_at: Optional[datetime] = None
|
||||
synthetic_storage_size_updated_at: Optional[datetime] = None
|
||||
data_transfer_bytes_updated_at: Optional[datetime] = None
|
||||
written_data_bytes_updated_at: Optional[datetime] = None
|
||||
compute_time_seconds_updated_at: Optional[datetime] = None
|
||||
active_time_seconds_updated_at: Optional[datetime] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Limits:
|
||||
active_time: int
|
||||
max_projects: int
|
||||
max_branches: int
|
||||
max_autoscaling_cu: float
|
||||
cpu_seconds: int
|
||||
max_active_endpoints: int
|
||||
max_read_only_endpoints: int
|
||||
max_allowed_ips: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectLimits:
|
||||
limits: Limits
|
||||
|
||||
|
||||
class BranchState(Enum):
|
||||
init = "init"
|
||||
ready = "ready"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Branch2:
|
||||
parent_id: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
parent_lsn: Optional[str] = None
|
||||
parent_timestamp: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Branch3:
|
||||
name: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BranchUpdateRequest:
|
||||
branch: Branch3
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConnectionParameters:
|
||||
database: str
|
||||
password: str
|
||||
role: str
|
||||
host: str
|
||||
pooler_host: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConnectionDetails:
|
||||
connection_uri: str
|
||||
connection_parameters: ConnectionParameters
|
||||
|
||||
|
||||
class EndpointState(Enum):
|
||||
init = "init"
|
||||
active = "active"
|
||||
idle = "idle"
|
||||
|
||||
|
||||
class EndpointType(Enum):
|
||||
read_only = "read_only"
|
||||
read_write = "read_write"
|
||||
|
||||
|
||||
class EndpointPoolerMode(Enum):
|
||||
transaction = "transaction"
|
||||
|
||||
|
||||
@dataclass
|
||||
class AllowedIps:
|
||||
primary_branch_only: bool
|
||||
ips: Optional[list[str]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConnectionURIsResponse:
|
||||
connection_uris: list[ConnectionDetails]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConnectionURIsOptionalResponse:
|
||||
connection_uris: Optional[list[ConnectionDetails]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class EndpointPasswordlessSessionAuthRequest:
|
||||
session_id: str
|
||||
|
||||
|
||||
Duration = int
|
||||
|
||||
|
||||
@dataclass
|
||||
class StatementData:
|
||||
truncated: bool
|
||||
fields: Optional[list[str]] = None
|
||||
rows: Optional[list[list[str]]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExplainData:
|
||||
QUERY_PLAN: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class Role:
|
||||
branch_id: str
|
||||
name: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
password: Optional[str] = None
|
||||
protected: Optional[bool] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Role1:
|
||||
name: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class RoleCreateRequest:
|
||||
role: Role1
|
||||
|
||||
|
||||
@dataclass
|
||||
class RoleResponse:
|
||||
role: Role
|
||||
|
||||
|
||||
@dataclass
|
||||
class RolesResponse:
|
||||
roles: list[Role]
|
||||
|
||||
|
||||
@dataclass
|
||||
class RolePasswordResponse:
|
||||
password: str
|
||||
|
||||
|
||||
class Brand(Enum):
|
||||
amex = "amex"
|
||||
diners = "diners"
|
||||
discover = "discover"
|
||||
jcb = "jcb"
|
||||
mastercard = "mastercard"
|
||||
unionpay = "unionpay"
|
||||
unknown = "unknown"
|
||||
visa = "visa"
|
||||
|
||||
|
||||
@dataclass
|
||||
class PaymentSourceBankCard:
|
||||
last4: str
|
||||
brand: Optional[Brand] = None
|
||||
exp_month: Optional[int] = None
|
||||
exp_year: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class PaymentSource:
|
||||
type: str
|
||||
card: Optional[PaymentSourceBankCard] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BillingAccount1:
|
||||
email: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BillingAccountUpdateRequest:
|
||||
billing_account: BillingAccount1
|
||||
|
||||
|
||||
class BillingSubscriptionType(Enum):
|
||||
UNKNOWN = "UNKNOWN"
|
||||
free = "free"
|
||||
pro = "pro"
|
||||
direct_sales = "direct_sales"
|
||||
aws_marketplace = "aws_marketplace"
|
||||
free_v2 = "free_v2"
|
||||
launch = "launch"
|
||||
scale = "scale"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Database:
|
||||
id: int
|
||||
branch_id: str
|
||||
name: str
|
||||
owner_name: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class Database1:
|
||||
name: str
|
||||
owner_name: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabaseCreateRequest:
|
||||
database: Database1
|
||||
|
||||
|
||||
@dataclass
|
||||
class Database2:
|
||||
name: Optional[str] = None
|
||||
owner_name: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabaseUpdateRequest:
|
||||
database: Database2
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabaseResponse:
|
||||
database: Database
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabasesResponse:
|
||||
databases: list[Database]
|
||||
|
||||
|
||||
@dataclass
|
||||
class CurrentUserAuthAccount:
|
||||
email: str
|
||||
image: str
|
||||
login: str
|
||||
name: str
|
||||
provider: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class UpdateUserInfoRequest:
|
||||
email: str
|
||||
id: str
|
||||
image: Optional[str] = None
|
||||
first_name: Optional[str] = None
|
||||
last_name: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectQuota:
|
||||
active_time_seconds: Optional[int] = None
|
||||
compute_time_seconds: Optional[int] = None
|
||||
written_data_bytes: Optional[int] = None
|
||||
data_transfer_bytes: Optional[int] = None
|
||||
logical_size_bytes: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class HealthCheck:
|
||||
status: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectOwnerData:
|
||||
email: str
|
||||
branches_limit: int
|
||||
subscription_type: BillingSubscriptionType
|
||||
|
||||
|
||||
class SupportTicketSeverity(Enum):
|
||||
low = "low"
|
||||
normal = "normal"
|
||||
high = "high"
|
||||
critical = "critical"
|
||||
|
||||
|
||||
@dataclass
|
||||
class PaginationResponse:
|
||||
pagination: Optional[Pagination] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Operation:
|
||||
id: str
|
||||
project_id: str
|
||||
action: OperationAction
|
||||
status: OperationStatus
|
||||
failures_count: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
total_duration_ms: int
|
||||
branch_id: Optional[str] = None
|
||||
endpoint_id: Optional[str] = None
|
||||
error: Optional[str] = None
|
||||
retry_at: Optional[datetime] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class OperationResponse:
|
||||
operation: Operation
|
||||
|
||||
|
||||
@dataclass
|
||||
class OperationsResponse:
|
||||
operations: list[Operation]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectSettingsData:
|
||||
quota: Optional[ProjectQuota] = None
|
||||
allowed_ips: Optional[AllowedIps] = None
|
||||
enable_logical_replication: Optional[bool] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectsConsumptionResponse:
|
||||
projects: list[ProjectConsumption]
|
||||
periods_in_response: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class Branch1:
|
||||
id: str
|
||||
project_id: str
|
||||
name: str
|
||||
current_state: BranchState
|
||||
creation_source: str
|
||||
primary: bool
|
||||
cpu_used_sec: int
|
||||
compute_time_seconds: int
|
||||
active_time_seconds: int
|
||||
written_data_bytes: int
|
||||
data_transfer_bytes: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
parent_id: Optional[str] = None
|
||||
parent_lsn: Optional[str] = None
|
||||
parent_timestamp: Optional[str] = None
|
||||
pending_state: Optional[BranchState] = None
|
||||
logical_size: Optional[int] = None
|
||||
last_reset_at: Optional[datetime] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BranchCreateRequestEndpointOptions:
|
||||
type: EndpointType
|
||||
autoscaling_limit_min_cu: Optional[float] = None
|
||||
autoscaling_limit_max_cu: Optional[float] = None
|
||||
provisioner: Optional[Provisioner] = None
|
||||
suspend_timeout_seconds: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BranchCreateRequest:
|
||||
endpoints: Optional[list[BranchCreateRequestEndpointOptions]] = None
|
||||
branch: Optional[Branch2] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BranchResponse:
|
||||
branch: Branch1
|
||||
|
||||
|
||||
@dataclass
|
||||
class BranchesResponse:
|
||||
branches: list[Branch1]
|
||||
|
||||
|
||||
@dataclass
|
||||
class StatementResult:
|
||||
query: str
|
||||
data: Optional[StatementData] = None
|
||||
error: Optional[str] = None
|
||||
explain_data: Optional[list[ExplainData]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BillingAccount:
|
||||
payment_source: PaymentSource
|
||||
subscription_type: BillingSubscriptionType
|
||||
quota_reset_at_last: str
|
||||
email: str
|
||||
address_city: str
|
||||
address_country: str
|
||||
address_line1: str
|
||||
address_line2: str
|
||||
address_postal_code: str
|
||||
address_state: str
|
||||
orb_portal_url: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BillingAccountResponse:
|
||||
billing_account: BillingAccount
|
||||
|
||||
|
||||
@dataclass
|
||||
class CurrentUserInfoResponse:
|
||||
active_seconds_limit: int
|
||||
billing_account: BillingAccount
|
||||
auth_accounts: list[CurrentUserAuthAccount]
|
||||
email: str
|
||||
id: str
|
||||
image: str
|
||||
login: str
|
||||
name: str
|
||||
last_name: str
|
||||
projects_limit: int
|
||||
branches_limit: int
|
||||
max_autoscaling_limit: float
|
||||
plan: str
|
||||
compute_seconds_limit: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class EndpointSettingsData:
|
||||
pg_settings: Optional[dict[str, str]] = None
|
||||
pgbouncer_settings: Optional[dict[str, str]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class DefaultEndpointSettings:
|
||||
pg_settings: Optional[dict[str, str]] = None
|
||||
pgbouncer_settings: Optional[dict[str, str]] = None
|
||||
autoscaling_limit_min_cu: Optional[float] = None
|
||||
autoscaling_limit_max_cu: Optional[float] = None
|
||||
suspend_timeout_seconds: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class GeneralError:
|
||||
code: str
|
||||
message: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class BranchOperations(BranchResponse, OperationsResponse):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabaseOperations(DatabaseResponse, OperationsResponse):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class RoleOperations(RoleResponse, OperationsResponse):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectListItem:
|
||||
id: str
|
||||
platform_id: str
|
||||
region_id: str
|
||||
name: str
|
||||
provisioner: Provisioner
|
||||
pg_version: int
|
||||
proxy_host: str
|
||||
branch_logical_size_limit: int
|
||||
branch_logical_size_limit_bytes: int
|
||||
store_passwords: bool
|
||||
active_time: int
|
||||
cpu_used_sec: int
|
||||
creation_source: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
owner_id: str
|
||||
default_endpoint_settings: Optional[DefaultEndpointSettings] = None
|
||||
settings: Optional[ProjectSettingsData] = None
|
||||
maintenance_starts_at: Optional[datetime] = None
|
||||
synthetic_storage_size: Optional[int] = None
|
||||
quota_reset_at: Optional[datetime] = None
|
||||
compute_last_active_at: Optional[datetime] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Project:
|
||||
data_storage_bytes_hour: int
|
||||
data_transfer_bytes: int
|
||||
written_data_bytes: int
|
||||
compute_time_seconds: int
|
||||
active_time_seconds: int
|
||||
cpu_used_sec: int
|
||||
id: str
|
||||
platform_id: str
|
||||
region_id: str
|
||||
name: str
|
||||
provisioner: Provisioner
|
||||
pg_version: int
|
||||
proxy_host: str
|
||||
branch_logical_size_limit: int
|
||||
branch_logical_size_limit_bytes: int
|
||||
store_passwords: bool
|
||||
creation_source: str
|
||||
history_retention_seconds: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
consumption_period_start: str
|
||||
consumption_period_end: str
|
||||
owner_id: str
|
||||
default_endpoint_settings: Optional[DefaultEndpointSettings] = None
|
||||
settings: Optional[ProjectSettingsData] = None
|
||||
maintenance_starts_at: Optional[datetime] = None
|
||||
synthetic_storage_size: Optional[int] = None
|
||||
quota_reset_at: Optional[datetime] = None
|
||||
owner: Optional[ProjectOwnerData] = None
|
||||
compute_last_active_at: Optional[datetime] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Project1:
|
||||
settings: Optional[ProjectSettingsData] = None
|
||||
name: Optional[str] = None
|
||||
branch: Optional[Branch] = None
|
||||
autoscaling_limit_min_cu: Optional[float] = None
|
||||
autoscaling_limit_max_cu: Optional[float] = None
|
||||
provisioner: Optional[Provisioner] = None
|
||||
region_id: Optional[str] = None
|
||||
default_endpoint_settings: Optional[DefaultEndpointSettings] = None
|
||||
pg_version: Optional[int] = None
|
||||
store_passwords: Optional[bool] = None
|
||||
history_retention_seconds: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectCreateRequest:
|
||||
project: Project1
|
||||
|
||||
|
||||
@dataclass
|
||||
class Project2:
|
||||
settings: Optional[ProjectSettingsData] = None
|
||||
name: Optional[str] = None
|
||||
default_endpoint_settings: Optional[DefaultEndpointSettings] = None
|
||||
history_retention_seconds: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectUpdateRequest:
|
||||
project: Project2
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectResponse:
|
||||
project: Project
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProjectsResponse:
|
||||
projects: list[ProjectListItem]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Endpoint:
|
||||
host: str
|
||||
id: str
|
||||
project_id: str
|
||||
branch_id: str
|
||||
autoscaling_limit_min_cu: float
|
||||
autoscaling_limit_max_cu: float
|
||||
region_id: str
|
||||
type: EndpointType
|
||||
current_state: EndpointState
|
||||
settings: EndpointSettingsData
|
||||
pooler_enabled: bool
|
||||
pooler_mode: EndpointPoolerMode
|
||||
disabled: bool
|
||||
passwordless_access: bool
|
||||
creation_source: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
proxy_host: str
|
||||
suspend_timeout_seconds: int
|
||||
provisioner: Provisioner
|
||||
pending_state: Optional[EndpointState] = None
|
||||
last_active: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Endpoint1:
|
||||
branch_id: str
|
||||
type: EndpointType
|
||||
region_id: Optional[str] = None
|
||||
settings: Optional[EndpointSettingsData] = None
|
||||
autoscaling_limit_min_cu: Optional[float] = None
|
||||
autoscaling_limit_max_cu: Optional[float] = None
|
||||
provisioner: Optional[Provisioner] = None
|
||||
pooler_enabled: Optional[bool] = None
|
||||
pooler_mode: Optional[EndpointPoolerMode] = None
|
||||
disabled: Optional[bool] = None
|
||||
passwordless_access: Optional[bool] = None
|
||||
suspend_timeout_seconds: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class EndpointCreateRequest:
|
||||
endpoint: Endpoint1
|
||||
|
||||
|
||||
@dataclass
|
||||
class Endpoint2:
|
||||
branch_id: Optional[str] = None
|
||||
autoscaling_limit_min_cu: Optional[float] = None
|
||||
autoscaling_limit_max_cu: Optional[float] = None
|
||||
provisioner: Optional[Provisioner] = None
|
||||
settings: Optional[EndpointSettingsData] = None
|
||||
pooler_enabled: Optional[bool] = None
|
||||
pooler_mode: Optional[EndpointPoolerMode] = None
|
||||
disabled: Optional[bool] = None
|
||||
passwordless_access: Optional[bool] = None
|
||||
suspend_timeout_seconds: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class EndpointUpdateRequest:
|
||||
endpoint: Endpoint2
|
||||
|
||||
|
||||
@dataclass
|
||||
class EndpointResponse:
|
||||
endpoint: Endpoint
|
||||
|
||||
|
||||
@dataclass
|
||||
class EndpointsResponse:
|
||||
endpoints: list[Endpoint]
|
||||
|
||||
|
||||
@dataclass
|
||||
class EndpointOperations(EndpointResponse, OperationsResponse):
|
||||
pass
|
||||
@@ -0,0 +1,23 @@
|
||||
import datetime
|
||||
|
||||
|
||||
def compact_mapping(obj):
|
||||
"""Compact a dict/mapping by removing all None values."""
|
||||
|
||||
return {k: v for k, v in obj.items() if v is not None}
|
||||
|
||||
|
||||
def to_iso8601(dt):
|
||||
"""Convert a datetime object to an
|
||||
`ISO 8601 <https://www.iso.org/iso-8601-date-and-time-format.html>`_ string.
|
||||
"""
|
||||
|
||||
return dt.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
def from_iso8601(s):
|
||||
"""Convert an `ISO 8601 <https://www.iso.org/iso-8601-date-and-time-format.html>`_
|
||||
string to a datetime object.
|
||||
"""
|
||||
|
||||
return datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ")
|
||||
Reference in New Issue
Block a user