Compare commits

...

7 Commits

Author SHA1 Message Date
7ee7964440 update makefile
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2021-12-14 18:51:57 -08:00
789f0b2a3b fix the client
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2021-12-14 18:39:22 -08:00
62b021d566 bump the version
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2021-12-14 18:38:16 -08:00
27266e32ec update
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2021-12-14 18:29:47 -08:00
7b445af622 Update README.md 2021-12-14 18:19:40 -08:00
4366d70775 fix
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2021-12-08 14:47:38 -08:00
5eb7401824 fix readme
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2021-12-08 14:46:08 -08:00
14 changed files with 69 additions and 115 deletions

View File

@ -5,6 +5,10 @@ ifeq ($(INTERACTIVE), 1)
DOCKER_FLAGS += -t
endif
# For this to work, you need to install toml-cli: https://github.com/gnprice/toml-cli
# `cargo install toml-cli`
VERSION := $(shell toml get $(CURDIR)/kittycad/pyproject.toml tool.poetry.version | jq -r .)
.PHONY: generate
generate: docker-image
docker run --rm -i $(DOCKER_FLAGS) \
@ -19,6 +23,10 @@ generate: docker-image
docker-image:
docker build -t $(DOCKER_IMAGE_NAME) .
.PHONY: tag
tag: ## Create a new git tag to prepare to build a release.
git tag -sa "v$(VERSION)" -m "v$(VERSION)"
@echo "Run git push origin v$(VERSION) to push your new tag to GitHub and trigger a release."
.PHONY: help
help:

View File

@ -5,6 +5,9 @@ The Python API client for KittyCAD.
This is generated from
[openapi-generators/openapi-python-client](https://github.com/openapi-generators/openapi-python-client).
- [PyPI](https://pypi.org/project/kittycad/)
- [KittyCAD API Docs](https://docs.kittycad.io/?lang=python)
## Generating
You can trigger a build with the GitHub action to generate the client. This will

View File

@ -2,86 +2,42 @@
A client library for accessing KittyCAD
## Usage
First, create a client:
```python
from kittycad import Client
client = Client(base_url="https://api.example.com")
```
If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead:
First, create an authenticated client:
```python
from kittycad import AuthenticatedClient
client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken")
client = AuthenticatedClient(token="your_token")
```
If you want to use the environment variable `KITTYCAD_API_TOKEN` to do
authentication and not pass one to the client, do the following:
```python
from kittycad import AuthenticatedClientFromEnv
client = AuthenticatedClientFromEnv()
```
Now call your endpoint and use your models:
```python
from kittycad.models import MyDataModel
from kittycad.api.my_tag import get_my_data_model
from kittycad.models import AuthSession
from kittycad.api.meta import meta_debug_session
from kittycad.types import Response
my_data: MyDataModel = get_my_data_model.sync(client=client)
session: AuthSession = meta_debug_session.sync(client=client)
# or if you need more info (e.g. status_code)
response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client)
response: Response[AuthSession] = meta_debug_session.sync_detailed(client=client)
```
Or do the same thing with an async version:
```python
from kittycad.models import MyDataModel
from kittycad.api.my_tag import get_my_data_model
from kittycad.models import AuthSession
from kittycad.api.meta import meta_debug_session
from kittycad.types import Response
my_data: MyDataModel = await get_my_data_model.asyncio(client=client)
response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client)
session: AuthSession = await meta_debug_session.asyncio(client=client)
response: Response[AuthSession] = await meta_debug_session.asyncio_detailed(client=client)
```
By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle.
```python
client = AuthenticatedClient(
base_url="https://internal_api.example.com",
token="SuperSecretToken",
verify_ssl="/path/to/certificate_bundle.pem",
)
```
You can also disable certificate validation altogether, but beware that **this is a security risk**.
```python
client = AuthenticatedClient(
base_url="https://internal_api.example.com",
token="SuperSecretToken",
verify_ssl=False
)
```
Things to know:
1. Every path/method combo becomes a Python module with four functions:
1. `sync`: Blocking request that returns parsed data (if successful) or `None`
1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful.
1. `asyncio`: Like `sync` but the async instead of blocking
1. `asyncio_detailed`: Like `sync_detailed` by async instead of blocking
1. All path/query params, and bodies become method arguments.
1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above)
1. Any endpoint which did not have a tag will be in `kittycad.api.default`
## Building / publishing this Client
This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics:
1. Update the metadata in pyproject.toml (e.g. authors, version)
1. If you're using a private repository, configure it with Poetry
1. `poetry config repositories.<your-repository-name> <url-to-your-repository>`
1. `poetry config http-basic.<your-repository-name> <username> <password>`
1. Publish the client with `poetry publish --build -r <your-repository-name>` or, if for public PyPI, just `poetry publish --build`
If you want to install this client into another project without publishing it (e.g. for development) then:
1. If that project **is using Poetry**, you can simply do `poetry add <path-to-this-client>` from that project
1. If that project is not using Poetry:
1. Build a wheel with `poetry build -f wheel`
1. Install that wheel from the other project `pip install <path-to-wheel>`

View File

@ -50,6 +50,10 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[Any, FileConv
response_406 = None
return response_406
if response.status_code == 500:
response_500 = None
return response_500
return None

View File

@ -54,6 +54,10 @@ def _parse_response(*, response: httpx.Response) -> Optional[Union[Any, FileConv
response_406 = None
return response_406
if response.status_code == 500:
response_500 = None
return response_500
return None

View File

@ -3,7 +3,7 @@ from typing import Any, Dict, Optional
import httpx
from ...client import Client
from ...models.ping_response_200 import PingResponse200
from ...models.message import Message
from ...types import Response
@ -24,15 +24,15 @@ def _get_kwargs(
}
def _parse_response(*, response: httpx.Response) -> Optional[PingResponse200]:
def _parse_response(*, response: httpx.Response) -> Optional[Message]:
if response.status_code == 200:
response_200 = PingResponse200.from_dict(response.json())
response_200 = Message.from_dict(response.json())
return response_200
return None
def _build_response(*, response: httpx.Response) -> Response[PingResponse200]:
def _build_response(*, response: httpx.Response) -> Response[Message]:
return Response(
status_code=response.status_code,
content=response.content,
@ -44,7 +44,7 @@ def _build_response(*, response: httpx.Response) -> Response[PingResponse200]:
def sync_detailed(
*,
client: Client,
) -> Response[PingResponse200]:
) -> Response[Message]:
kwargs = _get_kwargs(
client=client,
)
@ -60,7 +60,7 @@ def sync_detailed(
def sync(
*,
client: Client,
) -> Optional[PingResponse200]:
) -> Optional[Message]:
"""Simple ping to the server."""
return sync_detailed(
@ -71,7 +71,7 @@ def sync(
async def asyncio_detailed(
*,
client: Client,
) -> Response[PingResponse200]:
) -> Response[Message]:
kwargs = _get_kwargs(
client=client,
)
@ -85,7 +85,7 @@ async def asyncio_detailed(
async def asyncio(
*,
client: Client,
) -> Optional[PingResponse200]:
) -> Optional[Message]:
"""Simple ping to the server."""
return (

View File

@ -1,4 +1,3 @@
import os
import ssl
from typing import Dict, Union
@ -47,13 +46,3 @@ class AuthenticatedClient(Client):
def get_headers(self) -> Dict[str, str]:
"""Get headers to be used in authenticated endpoints"""
return {"Authorization": f"Bearer {self.token}", **self.headers}
@attr.s(auto_attribs=True)
class AuthenticatedClientFromEnv(Client):
"""A Client which has been authenticated for use on secured endpoints that uses the KITTYCAD_API_TOKEN environment variable for the authentication token."""
token: str = attr.ib(default=os.getenv('KITTYCAD_API_TOKEN'))
def get_headers(self) -> Dict[str, str]:
"""Get headers to be used in authenticated endpoints"""
return {"Authorization": f"Bearer {self.token}", **self.headers}

View File

@ -1,11 +1,10 @@
""" Contains all the data models used in inputs/outputs """
from .auth_session import AuthSession
from .environment import Environment
from .error_message import ErrorMessage
from .file_conversion import FileConversion
from .file_conversion_status import FileConversionStatus
from .instance_metadata import InstanceMetadata
from .instance_metadata_environment import InstanceMetadataEnvironment
from .ping_response_200 import PingResponse200
from .ping_response_200_message import PingResponse200Message
from .message import Message
from .valid_file_types import ValidFileTypes

View File

@ -14,6 +14,7 @@ class AuthSession:
""" """
created_at: Union[Unset, datetime.datetime] = UNSET
email: Union[Unset, str] = UNSET
id: Union[Unset, str] = UNSET
ip_address: Union[Unset, str] = UNSET
is_valid: Union[Unset, bool] = False
@ -26,6 +27,7 @@ class AuthSession:
if not isinstance(self.created_at, Unset):
created_at = self.created_at.isoformat()
email = self.email
id = self.id
ip_address = self.ip_address
is_valid = self.is_valid
@ -37,6 +39,8 @@ class AuthSession:
field_dict.update({})
if created_at is not UNSET:
field_dict["created_at"] = created_at
if email is not UNSET:
field_dict["email"] = email
if id is not UNSET:
field_dict["id"] = id
if ip_address is not UNSET:
@ -60,6 +64,8 @@ class AuthSession:
else:
created_at = isoparse(_created_at)
email = d.pop("email", UNSET)
id = d.pop("id", UNSET)
ip_address = d.pop("ip_address", UNSET)
@ -72,6 +78,7 @@ class AuthSession:
auth_session = cls(
created_at=created_at,
email=email,
id=id,
ip_address=ip_address,
is_valid=is_valid,

View File

@ -1,7 +1,7 @@
from enum import Enum
class InstanceMetadataEnvironment(str, Enum):
class Environment(str, Enum):
DEVELOPMENT = "DEVELOPMENT"
PREVIEW = "PREVIEW"
PRODUCTION = "PRODUCTION"

View File

@ -2,7 +2,7 @@ from typing import Any, Dict, List, Type, TypeVar, Union
import attr
from ..models.instance_metadata_environment import InstanceMetadataEnvironment
from ..models.environment import Environment
from ..types import UNSET, Unset
T = TypeVar("T", bound="InstanceMetadata")
@ -14,7 +14,7 @@ class InstanceMetadata:
cpu_platform: Union[Unset, str] = UNSET
description: Union[Unset, str] = UNSET
environment: Union[Unset, InstanceMetadataEnvironment] = UNSET
environment: Union[Unset, Environment] = UNSET
git_hash: Union[Unset, str] = UNSET
hostname: Union[Unset, str] = UNSET
id: Union[Unset, str] = UNSET
@ -77,11 +77,11 @@ class InstanceMetadata:
description = d.pop("description", UNSET)
_environment = d.pop("environment", UNSET)
environment: Union[Unset, InstanceMetadataEnvironment]
environment: Union[Unset, Environment]
if isinstance(_environment, Unset):
environment = UNSET
else:
environment = InstanceMetadataEnvironment(_environment)
environment = Environment(_environment)
git_hash = d.pop("git_hash", UNSET)

View File

@ -2,23 +2,20 @@ from typing import Any, Dict, List, Type, TypeVar, Union
import attr
from ..models.ping_response_200_message import PingResponse200Message
from ..types import UNSET, Unset
T = TypeVar("T", bound="PingResponse200")
T = TypeVar("T", bound="Message")
@attr.s(auto_attribs=True)
class PingResponse200:
class Message:
""" """
message: Union[Unset, PingResponse200Message] = UNSET
message: Union[Unset, str] = UNSET
additional_properties: Dict[str, Any] = attr.ib(init=False, factory=dict)
def to_dict(self) -> Dict[str, Any]:
message: Union[Unset, str] = UNSET
if not isinstance(self.message, Unset):
message = self.message.value
message = self.message
field_dict: Dict[str, Any] = {}
field_dict.update(self.additional_properties)
@ -31,19 +28,14 @@ class PingResponse200:
@classmethod
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
d = src_dict.copy()
_message = d.pop("message", UNSET)
message: Union[Unset, PingResponse200Message]
if isinstance(_message, Unset):
message = UNSET
else:
message = PingResponse200Message(_message)
message = d.pop("message", UNSET)
ping_response_200 = cls(
message = cls(
message=message,
)
ping_response_200.additional_properties = d
return ping_response_200
message.additional_properties = d
return message
@property
def additional_keys(self) -> List[str]:

View File

@ -1,8 +0,0 @@
from enum import Enum
class PingResponse200Message(str, Enum):
PONG = "pong"
def __str__(self) -> str:
return str(self.value)

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "kittycad"
version = "0.0.1"
version = "0.0.3"
description = "A client library for accessing KittyCAD"
authors = []