pyrest-model-client 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ from dotenv import load_dotenv
2
+
3
+ from pyrest_model_client.client import RequestClient, build_header
4
+ from pyrest_model_client.base import BaseAPIModel, set_client
5
+
6
+ load_dotenv()
7
+
8
+ __all__ = [
9
+ "RequestClient",
10
+ "build_header",
11
+ "BaseAPIModel",
12
+ "set_client",
13
+ ]
@@ -0,0 +1,45 @@
1
+ from typing import ClassVar
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from pyrest_model_client.client import RequestClient
6
+
7
+
8
+ def set_client(new_client: RequestClient):
9
+ """Set the global client instance for all API models."""
10
+ global client
11
+ client = new_client
12
+
13
+
14
+ class BaseAPIModel(BaseModel):
15
+ id: int | str | None = None
16
+ _resource_path: ClassVar[str] = ""
17
+
18
+ def save(self) -> None:
19
+ data = self.model_dump(exclude_unset=True)
20
+ if self.id:
21
+ response = client.put(f"/{self._resource_path}/{self.id}", json=data)
22
+ else:
23
+ response = client.post(f"/{self._resource_path}", json=data)
24
+ response.raise_for_status()
25
+ self.id = response.json()["id"]
26
+
27
+ def delete(self) -> None:
28
+ if not self.id:
29
+ raise ValueError("Cannot delete unsaved resource.")
30
+ response = client.delete(f"/{self._resource_path}/{self.id}")
31
+ response.raise_for_status()
32
+
33
+ @classmethod
34
+ def load(cls, resource_id: str):
35
+ response = client.get(f"/{cls._resource_path}/{resource_id}")
36
+ if response.status_code == 404:
37
+ raise ValueError(f"{cls.__name__} not found.")
38
+ response.raise_for_status()
39
+ return cls(**response.json())
40
+
41
+ @classmethod
42
+ def find(cls):
43
+ response = client.get(f"/{cls._resource_path}")
44
+ response.raise_for_status()
45
+ return [cls(**item) for item in response.json()]
@@ -0,0 +1,50 @@
1
+ from typing import Optional
2
+
3
+ import httpx
4
+
5
+
6
+ def build_header(token: str, authorization_type: str = "Token", content_type: str = "application/json") -> dict:
7
+ return {
8
+ "Content-Type": content_type,
9
+ "Authorization": f"{authorization_type} {token}",
10
+ }
11
+
12
+
13
+ class RequestClient:
14
+ def __init__(self, header: dict, base_url: str = "http://localhost:8000"):
15
+ self.base_url = base_url
16
+ self.client = httpx.Client(base_url=self.base_url)
17
+ self.set_credentials(header=header)
18
+
19
+ def set_credentials(self, header: dict):
20
+ self.client.headers.update(header)
21
+
22
+ def request(self, method: str, endpoint: str, **kwargs) -> httpx.Response:
23
+ if not endpoint.startswith("http://") and not endpoint.startswith("https://"):
24
+ if not endpoint.startswith("/"): # Ensure endpoint starts with a slash if it's a path (not a full URL)
25
+ endpoint = "/" + endpoint
26
+
27
+ if not endpoint.endswith("/"): # Ensure endpoint ends with a slash
28
+ endpoint = endpoint + "/"
29
+
30
+ response = self.client.request(method, endpoint, **kwargs)
31
+ response.raise_for_status()
32
+ return response
33
+
34
+ def get(self, endpoint: str, params: Optional[dict] = None) -> httpx.Response:
35
+ if params is None:
36
+ params = {}
37
+ return self.request("GET", endpoint, params=params)
38
+
39
+ def post(self, endpoint: str, json: Optional[dict] = None) -> httpx.Response:
40
+ if json is None:
41
+ json = {}
42
+ return self.request("POST", endpoint, json=json)
43
+
44
+ def put(self, endpoint: str, json: Optional[dict] = None) -> httpx.Response:
45
+ if json is None:
46
+ json = {}
47
+ return self.request("PUT", endpoint, json=json)
48
+
49
+ def delete(self, endpoint: str) -> httpx.Response:
50
+ return self.request("DELETE", endpoint)
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyrest-model-client
3
+ Version: 0.0.1
4
+ Summary: A simple, flexible Python HTTP client and API modeling toolkit built on httpx and pydantic.
5
+ Home-page: https://github.com/aviz92/pyrest-model-client
6
+ Author: Avi Zaguri
7
+ Author-email:
8
+ Project-URL: Repository, https://github.com/aviz92/pyrest-model-client
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: setuptools
13
+ Requires-Dist: dotenv
14
+ Requires-Dist: wheel
15
+ Requires-Dist: colorlog
16
+ Requires-Dist: pytest
17
+ Requires-Dist: pathlib
18
+ Requires-Dist: httpx
19
+ Requires-Dist: pydantic
20
+ Requires-Dist: custom-python-logger
21
+ Requires-Dist: pytest-plugins
22
+ Requires-Dist: python-simple-email-sender
23
+ Requires-Dist: python-vault
24
+ Requires-Dist: PyYAML
25
+ Requires-Dist: pytest-asyncio
26
+ Dynamic: author
27
+ Dynamic: description
28
+ Dynamic: description-content-type
29
+ Dynamic: home-page
30
+ Dynamic: license-file
31
+ Dynamic: project-url
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ # python-requests-client
37
+
38
+ A simple, flexible Python HTTP client and API modeling toolkit built on top of [httpx](https://www.python-httpx.org/) and [pydantic](https://docs.pydantic.dev/). Easily integrate robust API requests and resource models into your Python projects.
39
+
40
+ ---
41
+
42
+ ## 🚀 Features
43
+ - **Model-driven**: Define and interact with API resources as Python classes.
44
+ - **Easy HTTP Requests**: Simple `RequestClient` for GET, POST, PUT, DELETE with automatic header and base URL management.
45
+ - **Pydantic API Models**: Define resource models with CRUD helpers (`save`, `delete`, `load`, `find`).
46
+ - **Global Client Setup**: Set a global API client for all models with `set_client()`.
47
+ - **Type Safety**: All models use Pydantic for validation and serialization.
48
+ - **Extensible**: Easily create new models for any RESTful resource.
49
+
50
+ ---
51
+
52
+ ## 📦 Installation
53
+ ```bash
54
+ pip install python-requests-client
55
+ ```
56
+
57
+ ---
58
+
59
+ ## 🔧 Usage
60
+
61
+ ### 1. Define Your Models
62
+
63
+ ```python
64
+ from pyrest_model_client.base import BaseAPIModel
65
+ from typing import ClassVar
66
+
67
+
68
+ class User(BaseAPIModel):
69
+ name: str
70
+ email: str
71
+ _resource_path: ClassVar[str] = "user"
72
+
73
+
74
+ class Environment(BaseAPIModel):
75
+ name: str
76
+ _resource_path: ClassVar[str] = "environment"
77
+ ```
78
+
79
+ ### 2. Initialize the Client
80
+
81
+ ```python
82
+ from pyrest_model_client import RequestClient, build_header, set_client
83
+ from example_usage.models.user import User
84
+ from example_usage.models.environment import Environment
85
+
86
+ set_client(
87
+ new_client=RequestClient(
88
+ base_url="http://localhost:8000",
89
+ header=build_header(token="YOUR_API_TOKEN")
90
+ )
91
+ )
92
+
93
+ # Create and save a new user
94
+ e = User(name="Alice", email="alice@example.com")
95
+ e.save()
96
+
97
+ # Update and save
98
+ e.name = "Alice Smith"
99
+ e.save()
100
+
101
+ # Find all environments
102
+ environments = Environment.find()
103
+ print(environments)
104
+
105
+ # Load a specific user by ID
106
+ user = User.load(resource_id="123")
107
+
108
+ # Delete a user
109
+ user.delete()
110
+ ```
111
+
112
+ ---
113
+
114
+ ## 🤝 Contributing
115
+ Contributions are welcome! Please fork the repo, create a branch, and submit a pull request.
116
+
117
+ ---
118
+
119
+ ## 📄 License
120
+ MIT License — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,8 @@
1
+ pyrest_model_client/__init__.py,sha256=4CE5p2_nPxK7yAElL32waZFhvw-mBrJv2Slx-8UzoF0,270
2
+ pyrest_model_client/base.py,sha256=4mbheCcAi8cveq7ceUfREBvwBRNSZF1jVdGXREOjNsU,1420
3
+ pyrest_model_client/client.py,sha256=ke167iQBPg0pUFmVirJREHLF8AIw5cqAvQ2cJa1mw-M,1838
4
+ pyrest_model_client-0.0.1.dist-info/licenses/LICENSE,sha256=cSikHY6SZFsPZSBizCDAJ0-Bjjzxt-JtX6TVbKxwimo,1067
5
+ pyrest_model_client-0.0.1.dist-info/METADATA,sha256=UJ6EQMWMLZ_aYmiyt2XSRESnsgU5bHDIlZQX-C-DBnA,3078
6
+ pyrest_model_client-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ pyrest_model_client-0.0.1.dist-info/top_level.txt,sha256=HDtId78s9PTvfjerF5g7kRRe5Z91lgXlPr56w0E7wdU,20
8
+ pyrest_model_client-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Avi Zaguri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ pyrest_model_client