Skip to content

Commit 6befc34

Browse files
authored
Use pydantic (#28)
* Test 3.14 * Use pydantic * Use pydantic * Bump * Utility methods * Add space * few more docs * Bump dev * Few more methods
1 parent a880efa commit 6befc34

16 files changed

Lines changed: 1401 additions & 860 deletions

File tree

.github/workflows/build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
1717
strategy:
1818
matrix:
19-
python-version: ["3.11", "3.12", "3.13"]
19+
python-version: ["3.11", "3.12", "3.13", "3.14"]
2020

2121
steps:
2222
- uses: actions/checkout@v3
@@ -31,11 +31,11 @@ jobs:
3131
- name: run tests
3232
run: make test
3333
- name: upload coverage
34-
if: matrix.python-version == '3.13'
34+
if: matrix.python-version == '3.14'
3535
uses: codecov/codecov-action@v4
3636
with:
3737
token: ${{ secrets.CODECOV_TOKEN }}
3838
files: ./build/coverage.xml
3939
- name: release
40-
if: ${{matrix.python-version == '3.13' && github.ref == 'refs/heads/main' && github.event.head_commit.message == 'release'}}
40+
if: ${{matrix.python-version == '3.14' && github.ref == 'refs/heads/main' && github.event.head_commit.message == 'release'}}
4141
run: make publish

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2025 Quantmind
1+
Copyright (c) 2026 Quantmind
22

33
Redistribution and use in source and binary forms, with or without modification,
44
are permitted provided that the following conditions are met:

metablock/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
from .client import Metablock
22
from .components import MetablockEntity, MetablockError, MetablockResponseError
3-
from .extensions import Extension, Plugin
3+
from .extensions import Extension
44
from .orgs import Org
5-
from .spaces import Block, Service, Space, SpaceExtension
5+
from .spaces import Block, Space, SpaceExtension
66
from .user import User
77

8-
__version__ = "1.1.0"
8+
__version__ = "1.2.0"
99

1010
__all__ = [
1111
"Metablock",
1212
"MetablockError",
1313
"MetablockResponseError",
1414
"MetablockEntity",
1515
"Space",
16-
"Service",
1716
"Block",
1817
"Extension",
19-
"Plugin",
2018
"SpaceExtension",
2119
"Org",
2220
"User",

metablock/cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ async def _apply(path: str, space_name: str, token: str, dry_run: bool) -> None:
125125
raise click.Abort()
126126
async with Metablock(auth_key=token) as mb:
127127
space = await mb.spaces.get(space_name)
128-
svc = await space.blocks.get_list()
129-
click.echo(f"space {space.name} has {len(svc)} blocks")
130-
by_name = {s["name"]: s for s in svc}
128+
space_blocks = await space.blocks.get_list()
129+
click.echo(f"space {space.name} has {len(space_blocks)} blocks")
130+
by_name = {s.name: s for s in space_blocks}
131131
for name, config in blocks:
132132
block = by_name.get(name)
133133
if block:

metablock/client.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
from httpx import Response as ClientResponse
1010

1111
from .components import Callback, HttpComponent, MetablockResponseError
12-
from .extensions import Extension, Extensions, Plugin, Plugins
13-
from .orgs import Org, Orgs
14-
from .spaces import Block, Blocks, Domains, Space, Spaces
12+
from .extensions import Extensions
13+
from .orgs import Orgs
14+
from .spaces import Blocks, Domains, Spaces
1515
from .user import User
1616

1717
DEFAULT_USER_AGENT = f"Python/{'.'.join(map(str, sys.version_info[:2]))} metablock"
@@ -42,12 +42,11 @@ def __init__(
4242
"user-agent": user_agent,
4343
"accept": "application/json",
4444
}
45-
self.orgs: Orgs = Orgs(self, Org)
46-
self.spaces: Spaces = Spaces(self, Space)
47-
self.blocks: Blocks = Blocks(self, Block)
48-
self.plugins: Plugins = Plugins(self, Plugin)
49-
self.extensions: Extensions = Extensions(self, Extension)
50-
self.domains = Domains(self)
45+
self.orgs: Orgs = Orgs(root=self, root_path="orgs")
46+
self.spaces: Spaces = Spaces(root=self, root_path="spaces")
47+
self.blocks: Blocks = Blocks(root=self, root_path="blocks")
48+
self.extensions: Extensions = Extensions(root=self, root_path="extensions")
49+
self.domains = Domains(root=self, root_path="domains")
5150

5251
@property
5352
def cli(self) -> Self:
@@ -65,25 +64,31 @@ async def __aexit__(self, exc_type: type, exc_val: Any, exc_tb: Any) -> None:
6564
await self.close()
6665

6766
async def spec(self) -> dict:
67+
"""Get the OpenAPI specification of the API"""
6868
return await self.request(f"{self.url}/openapi.json")
6969

7070
async def get(self, url: str, **kwargs: Any) -> Any:
71+
"""Make a GET request to the API"""
7172
kwargs["method"] = "GET"
7273
return await self.request(url, **kwargs)
7374

7475
async def patch(self, url: str, **kwargs: Any) -> Any:
76+
"""Make a PATCH request to the API"""
7577
kwargs["method"] = "PATCH"
7678
return await self.request(url, **kwargs)
7779

7880
async def post(self, url: str, **kwargs: Any) -> Any:
81+
"""Make a POST request to the API"""
7982
kwargs["method"] = "POST"
8083
return await self.request(url, **kwargs)
8184

8285
async def put(self, url: str, **kwargs: Any) -> Any:
86+
"""Make a PUT request to the API"""
8387
kwargs["method"] = "PUT"
8488
return await self.request(url, **kwargs)
8589

8690
async def delete(self, url: str, **kwargs: Any) -> Any:
91+
"""Make a DELETE request to the API"""
8792
kwargs["method"] = "DELETE"
8893
return await self.request(url, **kwargs)
8994

@@ -96,6 +101,7 @@ async def request(
96101
wrap: Any = None,
97102
**kw: Any,
98103
) -> Any:
104+
"""Make a request to the API with the given method, url, headers and body."""
99105
if not self.session:
100106
self.session = AsyncClient()
101107
method = method or "GET"
@@ -122,22 +128,19 @@ async def handle_response(self, response: ClientResponse, wrap: Any = None) -> A
122128
data = response.json()
123129
return wrap(data) if wrap else data
124130

125-
async def get_user(self, **kw: Any) -> User:
126-
kw.setdefault("wrap", self._user)
127-
return await self.get(f"{self.url}/user", **kw)
131+
async def get_user(self, **kwargs: Any) -> User:
132+
data = await self.get(f"{self.url}/user", **kwargs)
133+
return User(root=self, root_path="user", **data)
128134

129-
async def update_user(self, **kw: Any) -> User:
130-
kw.setdefault("wrap", self._user)
131-
return await self.patch(f"{self.url}/user", **kw)
135+
async def update_user(self, **params: Any) -> User:
136+
data = await self.patch(f"{self.url}/user", **params)
137+
return User(root=self, root_path="user", **data)
132138

133-
async def delete_user(self, **kw: Any) -> None:
134-
return await self.delete(f"{self.url}/user", **kw)
139+
async def delete_user(self) -> None:
140+
return await self.delete(f"{self.url}/user")
135141

136142
def get_default_headers(self) -> dict[str, str]:
137143
headers = self.default_headers.copy()
138144
if self.auth_key:
139145
headers[self.auth_key_name] = self.auth_key
140146
return headers
141-
142-
def _user(self, data: dict) -> User:
143-
return User(self, data)

0 commit comments

Comments
 (0)