Skip to content

Commit

Permalink
Merge pull request #69 from ponytailer/simple-init
Browse files Browse the repository at this point in the history
feature(constructor): Simple init
  • Loading branch information
ponytailer authored Oct 8, 2024
2 parents ff36f34 + 9a63fcf commit 768e34f
Show file tree
Hide file tree
Showing 17 changed files with 107 additions and 182 deletions.
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ Only support the json response.
```python
from pydantic import BaseModel

from pydantic_client import delete, get, post, put, PydanticClient
from pydantic_client.clients import RequestsClient
from pydantic_client import delete, get, post, put, pydantic_client_factory
from pydantic_client import ClientConfig


Expand All @@ -34,6 +33,14 @@ class Book(BaseModel):
age: int


@pydantic_client_factory.register(
ClientConfig(
client_type="requests",
base_url="https://example.com",
headers={"Authorization": "Bearer abcdefg"},
timeout=10
)
)
class WebClient:

@get("/books/{book_id}?query={query}")
Expand All @@ -55,17 +62,7 @@ class WebClient:
...


client: WebClient = PydanticClient(
ClientConfig(
base_url="https://example.com",
headers={"Authorization": "Bearer abcdefg"},
timeout=10
)
).bind_client(RequestsClient) \
.bind_protocol(WebClient) \
.build()


client = pydantic_client_factory.get_client()
book: Book = client.get_book(1)

```
Expand All @@ -75,3 +72,5 @@ And see the examples to get more examples.
# change log

### v1.0.0: refactor all the code, to be simple. remove the group client.

### v1.0.1: simple to use.
17 changes: 10 additions & 7 deletions example/use_config_to_init.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from example.protocol import BookProtocol, Book
from pydantic_client import PydanticClient, ClientConfig
from pydantic_client.clients import RequestsClient
from example.protocol import BookProtocol, Book, AuthorProtocol, Author
from pydantic_client import pydantic_client_factory, ClientConfig

if __name__ == "__main__":
cfg = ClientConfig(
client_type="requests",
base_url="https://example.com/api"
)
client = PydanticClient(cfg) \
.bind_client(RequestsClient) \
.bind_protocol(BookProtocol) \
.build()

pydantic_client_factory.register(cfg)(BookProtocol)
pydantic_client_factory.register(cfg)(AuthorProtocol)

client = pydantic_client_factory.get_client(BookProtocol)
book: Book = client.get_book(1, "name")

author_client = pydantic_client_factory.get_client(AuthorProtocol)
author: Author = author_client.get_author()
12 changes: 0 additions & 12 deletions example/use_factory.py

This file was deleted.

11 changes: 0 additions & 11 deletions example/use_toml_to_init.py

This file was deleted.

5 changes: 3 additions & 2 deletions pydantic_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from pydantic_client.main import PydanticClient
from pydantic_client.schema.client_config import ClientConfig

pydantic_client_factory = PydanticClientFactory()

__all__ = [
"PydanticClient",
"PydanticClientFactory",
"pydantic_client_factory",
"ClientConfig",
"patch",
"get",
Expand Down
4 changes: 2 additions & 2 deletions pydantic_client/clients/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .requests import RequestsClient
from .aiohttp import AIOHttpClient
from .httpx import HttpxClient
from .httpx import HttpxClient
from .requests import RequestsClient
7 changes: 5 additions & 2 deletions pydantic_client/clients/aiohttp.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from typing import Any

from aiohttp.client import ClientSession

from pydantic_client.clients.abstract_client import AbstractClient
from pydantic_client.schema.http_request import HttpRequest

try:
from aiohttp.client import ClientSession
except ImportError:
raise ImportError("Please install `aiohttp` to use AIOHttpClient")


class AIOHttpClient(AbstractClient):

Expand Down
7 changes: 5 additions & 2 deletions pydantic_client/clients/httpx.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from typing import Any

from httpx import AsyncClient

from pydantic_client.clients.abstract_client import AbstractClient
from pydantic_client.schema.http_request import HttpRequest

try:
from httpx import AsyncClient
except ImportError:
raise ImportError("Please install `httpx` to use HttpxClient")


class HttpxClient(AbstractClient):

Expand Down
7 changes: 5 additions & 2 deletions pydantic_client/clients/requests.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from typing import Any

from requests import Session

from pydantic_client.clients.abstract_client import AbstractClient
from pydantic_client.schema.http_request import HttpRequest

try:
from requests import Session
except ImportError:
raise ImportError("Please install `requests` to use RequestsClient")


class RequestsClient(AbstractClient):
session = Session()
Expand Down
77 changes: 20 additions & 57 deletions pydantic_client/factory.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,36 @@
from pydantic_client.schema.client_config import FactoryConfig
from pydantic_client.schema.client_config import ClientConfig


class PydanticClientFactory:
"""
toml file example:
[[tools.pydantic_client.factory]]
name = "book_client
base_url = "https://example.com/api/v1"
timeout = 1
[[tools.pydantic_client.factory]]
name = "author_client
base_url = "https://example.com/api/v2"
timeout = 1
[[tools.pydantic_client.factory]]
name = "address_client
base_url = "https://example.com/api/v3"
timeout = 1
factory = PydanticClientFactory.from_toml("pydantic_client.toml") \
.register_client("book_client", RequestsClient, BookProtocol) \
.register_client("author_client", HttpxClient, AuthorProtocol)
.build()
book: Book = factory.get_client(BookProtocol).get_books(1)
"""

def __init__(self, config: FactoryConfig):
def __init__(self):
# name: client_class
self.pydantic_clients = {}
self.config = config

@classmethod
def from_toml(cls, toml_file: str) -> "PydanticClientFactory":
config = FactoryConfig.load_toml(toml_file)
return cls(config)
# self.config = config

def register_client(
def register(
self,
client_name: str,
client_class,
protocol_class,
*args,
**kwargs
client_config: ClientConfig
):
"""
params:
client_name: str, name of the client which in toml file.
client_class: client class which in pydantic-client.
protocol_class: protocol class which define the routers.
"""
cfg = self.config.get_by_name(client_name)
if not cfg:
raise ValueError(f"client {client_name} not found in config")
def wrapper(protocol_class):
from pydantic_client.main import PydanticClient

from pydantic_client import PydanticClient
client = PydanticClient(client_config)

client = PydanticClient(cfg)
self.pydantic_clients[protocol_class] = client \
.bind_client(client_config.get_client()) \
.bind_protocol(protocol_class) \
.build()

self.pydantic_clients[protocol_class] = client \
.bind_client(client_class) \
.bind_protocol(protocol_class, *args, **kwargs) \
.build()
return self
return protocol_class

def build(self):
return self
return wrapper

def get_client(self, protocol_class):
def get_client(self, protocol_class=None):
if len(self.pydantic_clients) == 1:
return self.pydantic_clients[list(self.pydantic_clients.keys())[0]]
if not protocol_class:
raise ValueError(
"Multiple clients exists, protocol_class is required")
client = self.pydantic_clients.get(protocol_class)
if not client:
raise ValueError(f"client for {protocol_class} not found")
Expand Down
5 changes: 0 additions & 5 deletions pydantic_client/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ def __init__(self, config: ClientConfig):
self.client = None
self.protocol = None

@classmethod
def from_toml(cls, toml_path: str) -> "PydanticClient":
config = ClientConfig.load_toml(toml_path)
return cls(config=config)

def bind_client(self, client_class: Type[AbstractClient]):
self.client = client_class(self.config)
return self
Expand Down
18 changes: 17 additions & 1 deletion pydantic_client/schema/client_config.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import logging
from typing import Dict, Any, Optional
from typing import Dict, Any, Optional, Literal

from pydantic import BaseModel

logger = logging.getLogger(__name__)


class ClientConfig(BaseModel):
# unique name for the client
name: Optional[str] = None
# requests, httpx, aiohttp
client_type: Literal["requests", "httpx", "aiohttp"] = "requests"
base_url: str
headers: Dict[str, Any] = {}
# only httpx support http2
http2: bool = False
timeout: Optional[int] = None

def get_client(self):
if self.client_type == "requests":
from pydantic_client.clients import RequestsClient
return RequestsClient
elif self.client_type == "httpx":
from pydantic_client.clients import HttpxClient
return HttpxClient
else:
from pydantic_client.clients import AIOHttpClient
return AIOHttpClient

@classmethod
def load_toml(cls, path: str):
try:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pydantic-client"
version = "1.0.0"
version = "1.0.1"
description = "Http client base pydantic, with requests or aiohttp"
authors = ["ponytailer <[email protected]>"]
readme = "README.md"
Expand Down
12 changes: 0 additions & 12 deletions tests/config.toml

This file was deleted.

Loading

0 comments on commit 768e34f

Please sign in to comment.