webfunction 0.1.0__tar.gz
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.
- webfunction-0.1.0/.gitignore +6 -0
- webfunction-0.1.0/LICENSE +21 -0
- webfunction-0.1.0/PKG-INFO +100 -0
- webfunction-0.1.0/README.md +89 -0
- webfunction-0.1.0/examples/available_api_versions.py +39 -0
- webfunction-0.1.0/examples/available_api_versions_async.py +37 -0
- webfunction-0.1.0/pyproject.toml +20 -0
- webfunction-0.1.0/src/webfunction/__init__.py +44 -0
- webfunction-0.1.0/src/webfunction/_request.py +106 -0
- webfunction-0.1.0/src/webfunction/_version.py +1 -0
- webfunction-0.1.0/src/webfunction/client.py +296 -0
- webfunction-0.1.0/src/webfunction/errors.py +54 -0
- webfunction-0.1.0/src/webfunction/models.py +325 -0
- webfunction-0.1.0/src/webfunction/page.py +134 -0
- webfunction-0.1.0/src/webfunction/pipeline.py +163 -0
- webfunction-0.1.0/src/webfunction/py.typed +0 -0
- webfunction-0.1.0/src/webfunction/wftype.py +337 -0
- webfunction-0.1.0/tests/test_client.py +465 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
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,100 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: webfunction
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reference client library for the Web Function (wfn) protocol
|
|
5
|
+
Project-URL: Homepage, https://webfunction.org
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Requires-Dist: httpx>=0.24
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# webfunction-python
|
|
13
|
+
|
|
14
|
+
A reference client library for the [Web Function (wfn)](https://webfunction.org) protocol.
|
|
15
|
+
|
|
16
|
+
Part of the same reference-client suite as the Ruby gem
|
|
17
|
+
(`https://github.com/webfunction-protocol/webfunction-ruby`, the spec author's own implementation),
|
|
18
|
+
`webfunction-go`, `webfunction-java`, and `webfunction-csharp`.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install webfunction
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The only runtime dependency is [httpx](https://www.python-httpx.org/), which is what
|
|
27
|
+
lets this library offer both a synchronous `Client` and an async `AsyncClient` from a
|
|
28
|
+
single implementation.
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Sync
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from webfunction import Client
|
|
36
|
+
|
|
37
|
+
client = Client.from_package_endpoint("https://api.example.com/package")
|
|
38
|
+
result = client.list_items(email="a@example.com") # dynamic dispatch, no generated code
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Async
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import asyncio
|
|
45
|
+
from webfunction import AsyncClient
|
|
46
|
+
|
|
47
|
+
async def main():
|
|
48
|
+
client = await AsyncClient.from_package_endpoint("https://api.example.com/package")
|
|
49
|
+
result = await client.list_items(email="a@example.com")
|
|
50
|
+
|
|
51
|
+
asyncio.run(main())
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Pagination
|
|
55
|
+
|
|
56
|
+
Endpoints that declare the `paginated` flag return a `Page` (or `AsyncPage`):
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
page = client.list_people()
|
|
60
|
+
for person in page:
|
|
61
|
+
...
|
|
62
|
+
if page.has_next:
|
|
63
|
+
page = page.next_page()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Pipelining
|
|
67
|
+
|
|
68
|
+
If the package declares a `pipeline_url`, pass `pipelined=True` to batch several
|
|
69
|
+
endpoint invocations into a single request. Calls return a `Promise` instead of
|
|
70
|
+
executing immediately; index into a promise (`promise["id"]`) to build a reference to
|
|
71
|
+
one of its fields before it's resolved.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
client = Client.from_package_endpoint(url, pipelined=True)
|
|
75
|
+
item = client.list_items(email="a@example.com")
|
|
76
|
+
detail = client.get_widget(id=item["id"]) # references item's future "id" field
|
|
77
|
+
results = client.pipeline.execute()
|
|
78
|
+
print(detail.value)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Errors
|
|
82
|
+
|
|
83
|
+
All errors are subclasses of `WebFunctionError`, carrying `.code`, `.message`, and
|
|
84
|
+
`.details`: `BadRequestError`, `UnexpectedStatusCodeError`, `JsonParseError`,
|
|
85
|
+
`UnresolvedPromiseError`.
|
|
86
|
+
|
|
87
|
+
## A note on unknown fields
|
|
88
|
+
|
|
89
|
+
This library never validates incoming JSON against a strict schema -- model classes
|
|
90
|
+
only read the keys they know about via plain `dict.get()`, so an API that adds an
|
|
91
|
+
undocumented field to its responses (this has happened for real against
|
|
92
|
+
`api.reservepay.com`) won't break parsing the way it did for the Java client, which
|
|
93
|
+
needed an explicit fix to disable strict unknown-field rejection.
|
|
94
|
+
|
|
95
|
+
## Development
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install -e .
|
|
99
|
+
python -m unittest discover tests
|
|
100
|
+
```
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# webfunction-python
|
|
2
|
+
|
|
3
|
+
A reference client library for the [Web Function (wfn)](https://webfunction.org) protocol.
|
|
4
|
+
|
|
5
|
+
Part of the same reference-client suite as the Ruby gem
|
|
6
|
+
(`https://github.com/webfunction-protocol/webfunction-ruby`, the spec author's own implementation),
|
|
7
|
+
`webfunction-go`, `webfunction-java`, and `webfunction-csharp`.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install webfunction
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The only runtime dependency is [httpx](https://www.python-httpx.org/), which is what
|
|
16
|
+
lets this library offer both a synchronous `Client` and an async `AsyncClient` from a
|
|
17
|
+
single implementation.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Sync
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from webfunction import Client
|
|
25
|
+
|
|
26
|
+
client = Client.from_package_endpoint("https://api.example.com/package")
|
|
27
|
+
result = client.list_items(email="a@example.com") # dynamic dispatch, no generated code
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Async
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import asyncio
|
|
34
|
+
from webfunction import AsyncClient
|
|
35
|
+
|
|
36
|
+
async def main():
|
|
37
|
+
client = await AsyncClient.from_package_endpoint("https://api.example.com/package")
|
|
38
|
+
result = await client.list_items(email="a@example.com")
|
|
39
|
+
|
|
40
|
+
asyncio.run(main())
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Pagination
|
|
44
|
+
|
|
45
|
+
Endpoints that declare the `paginated` flag return a `Page` (or `AsyncPage`):
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
page = client.list_people()
|
|
49
|
+
for person in page:
|
|
50
|
+
...
|
|
51
|
+
if page.has_next:
|
|
52
|
+
page = page.next_page()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Pipelining
|
|
56
|
+
|
|
57
|
+
If the package declares a `pipeline_url`, pass `pipelined=True` to batch several
|
|
58
|
+
endpoint invocations into a single request. Calls return a `Promise` instead of
|
|
59
|
+
executing immediately; index into a promise (`promise["id"]`) to build a reference to
|
|
60
|
+
one of its fields before it's resolved.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
client = Client.from_package_endpoint(url, pipelined=True)
|
|
64
|
+
item = client.list_items(email="a@example.com")
|
|
65
|
+
detail = client.get_widget(id=item["id"]) # references item's future "id" field
|
|
66
|
+
results = client.pipeline.execute()
|
|
67
|
+
print(detail.value)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Errors
|
|
71
|
+
|
|
72
|
+
All errors are subclasses of `WebFunctionError`, carrying `.code`, `.message`, and
|
|
73
|
+
`.details`: `BadRequestError`, `UnexpectedStatusCodeError`, `JsonParseError`,
|
|
74
|
+
`UnresolvedPromiseError`.
|
|
75
|
+
|
|
76
|
+
## A note on unknown fields
|
|
77
|
+
|
|
78
|
+
This library never validates incoming JSON against a strict schema -- model classes
|
|
79
|
+
only read the keys they know about via plain `dict.get()`, so an API that adds an
|
|
80
|
+
undocumented field to its responses (this has happened for real against
|
|
81
|
+
`api.reservepay.com`) won't break parsing the way it did for the Java client, which
|
|
82
|
+
needed an explicit fix to disable strict unknown-field rejection.
|
|
83
|
+
|
|
84
|
+
## Development
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install -e .
|
|
88
|
+
python -m unittest discover tests
|
|
89
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Fetches the merchants package from api.reservepay.com and calls its
|
|
3
|
+
"available-api-versions" endpoint.
|
|
4
|
+
|
|
5
|
+
Requires a bearer token in the RESERVEPAY_BEARER_TOKEN environment variable:
|
|
6
|
+
|
|
7
|
+
RESERVEPAY_BEARER_TOKEN=... python examples/available_api_versions.py
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
from webfunction import Client, WebFunctionError
|
|
14
|
+
|
|
15
|
+
PACKAGE_URL = "https://api.reservepay.com/merchants"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main() -> int:
|
|
19
|
+
token = os.environ.get("RESERVEPAY_BEARER_TOKEN")
|
|
20
|
+
if not token:
|
|
21
|
+
print("RESERVEPAY_BEARER_TOKEN is not set.", file=sys.stderr)
|
|
22
|
+
print(f"Usage: RESERVEPAY_BEARER_TOKEN=... python {sys.argv[0]}", file=sys.stderr)
|
|
23
|
+
return 1
|
|
24
|
+
|
|
25
|
+
client = Client.from_package_endpoint(PACKAGE_URL, bearer_auth=token)
|
|
26
|
+
try:
|
|
27
|
+
versions = client.available_api_versions()
|
|
28
|
+
print(versions)
|
|
29
|
+
except WebFunctionError as e:
|
|
30
|
+
print(f"{type(e).__name__}: {e.message} (code={e.code}, details={e.details})", file=sys.stderr)
|
|
31
|
+
return 1
|
|
32
|
+
finally:
|
|
33
|
+
client.close()
|
|
34
|
+
|
|
35
|
+
return 0
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Async equivalent of available_api_versions.py.
|
|
3
|
+
|
|
4
|
+
RESERVEPAY_BEARER_TOKEN=... python examples/available_api_versions_async.py
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from webfunction import AsyncClient, WebFunctionError
|
|
12
|
+
|
|
13
|
+
PACKAGE_URL = "https://api.reservepay.com/merchants"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def run() -> int:
|
|
17
|
+
token = os.environ.get("RESERVEPAY_BEARER_TOKEN")
|
|
18
|
+
if not token:
|
|
19
|
+
print("RESERVEPAY_BEARER_TOKEN is not set.", file=sys.stderr)
|
|
20
|
+
print(f"Usage: RESERVEPAY_BEARER_TOKEN=... python {sys.argv[0]}", file=sys.stderr)
|
|
21
|
+
return 1
|
|
22
|
+
|
|
23
|
+
client = await AsyncClient.from_package_endpoint(PACKAGE_URL, bearer_auth=token)
|
|
24
|
+
try:
|
|
25
|
+
versions = await client.available_api_versions()
|
|
26
|
+
print(versions)
|
|
27
|
+
except WebFunctionError as e:
|
|
28
|
+
print(f"{type(e).__name__}: {e.message} (code={e.code}, details={e.details})", file=sys.stderr)
|
|
29
|
+
return 1
|
|
30
|
+
finally:
|
|
31
|
+
await client.aclose()
|
|
32
|
+
|
|
33
|
+
return 0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
raise SystemExit(asyncio.run(run()))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "webfunction"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Reference client library for the Web Function (wfn) protocol"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"httpx>=0.24",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://webfunction.org"
|
|
18
|
+
|
|
19
|
+
[tool.hatch.build.targets.wheel]
|
|
20
|
+
packages = ["src/webfunction"]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""webfunction -- a reference client library for the Web Function (wfn) protocol.
|
|
2
|
+
|
|
3
|
+
See https://webfunction.org for the protocol specification.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from ._version import VERSION
|
|
7
|
+
from .client import AsyncClient, Client
|
|
8
|
+
from .errors import (
|
|
9
|
+
BadRequestError,
|
|
10
|
+
JsonParseError,
|
|
11
|
+
UnexpectedStatusCodeError,
|
|
12
|
+
UnresolvedPromiseError,
|
|
13
|
+
WebFunctionError,
|
|
14
|
+
)
|
|
15
|
+
from .models import Argument, Attribute, DocumentedError, Endpoint, ObjectSchema, Package
|
|
16
|
+
from .page import AsyncPage, Page
|
|
17
|
+
from .pipeline import AsyncPipeline, Path, Pipeline, Promise
|
|
18
|
+
from . import wftype
|
|
19
|
+
|
|
20
|
+
__version__ = VERSION
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Client",
|
|
24
|
+
"AsyncClient",
|
|
25
|
+
"Package",
|
|
26
|
+
"Endpoint",
|
|
27
|
+
"Argument",
|
|
28
|
+
"Attribute",
|
|
29
|
+
"DocumentedError",
|
|
30
|
+
"ObjectSchema",
|
|
31
|
+
"Page",
|
|
32
|
+
"AsyncPage",
|
|
33
|
+
"Path",
|
|
34
|
+
"Promise",
|
|
35
|
+
"Pipeline",
|
|
36
|
+
"AsyncPipeline",
|
|
37
|
+
"WebFunctionError",
|
|
38
|
+
"BadRequestError",
|
|
39
|
+
"UnexpectedStatusCodeError",
|
|
40
|
+
"JsonParseError",
|
|
41
|
+
"UnresolvedPromiseError",
|
|
42
|
+
"wftype",
|
|
43
|
+
"VERSION",
|
|
44
|
+
]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Low-level HTTP request/response handling shared by Client and AsyncClient, ported
|
|
2
|
+
from the Ruby reference gem's request.rb.
|
|
3
|
+
|
|
4
|
+
Gzip note: the wfn protocol always sends ``Accept-Encoding: gzip`` explicitly. This has
|
|
5
|
+
bitten *every* prior client in the suite -- webfunction-go and webfunction-java both
|
|
6
|
+
independently broke on gzip response bodies because their HTTP libraries disable their
|
|
7
|
+
own automatic decompression once the caller sets ``Accept-Encoding`` itself.
|
|
8
|
+
httpx does NOT have this problem: it decides whether to decompress based on the
|
|
9
|
+
response's ``Content-Encoding`` header, regardless of who set ``Accept-Encoding`` on the
|
|
10
|
+
request (verified directly against a mock gzip-compressing server -- see
|
|
11
|
+
tests/test_client.py::test_gzip_response). So no manual gzip handling is needed here,
|
|
12
|
+
but it's still covered by a real test rather than just assumed.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from typing import Any, Dict, Optional
|
|
19
|
+
|
|
20
|
+
import httpx
|
|
21
|
+
|
|
22
|
+
from ._version import VERSION
|
|
23
|
+
from .errors import BadRequestError, JsonParseError, UnexpectedStatusCodeError
|
|
24
|
+
from .pipeline import Promise
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _json_default(obj: Any) -> Any:
|
|
28
|
+
if isinstance(obj, Promise):
|
|
29
|
+
return obj.to_json_value()
|
|
30
|
+
raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def dumps(obj: Any) -> bytes:
|
|
34
|
+
return json.dumps(obj, default=_json_default).encode("utf-8")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def build_headers(bearer_auth: Optional[str] = None, version: Optional[str] = None) -> Dict[str, str]:
|
|
38
|
+
headers = {
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
"Accept": "application/json",
|
|
41
|
+
"User-Agent": f"webfunction/{VERSION}",
|
|
42
|
+
"Accept-Encoding": "gzip",
|
|
43
|
+
}
|
|
44
|
+
if bearer_auth:
|
|
45
|
+
headers["Authorization"] = f"Bearer {bearer_auth}"
|
|
46
|
+
if version:
|
|
47
|
+
headers["Api-Version"] = version
|
|
48
|
+
return headers
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def parse_response(status: int, body: bytes) -> Any:
|
|
52
|
+
"""Parses a raw HTTP response per the wfn protocol, raising typed errors as needed.
|
|
53
|
+
Does not do pagination wrapping -- that needs the endpoint's ``paginated`` flag, which
|
|
54
|
+
only the caller (Client/AsyncClient) knows about."""
|
|
55
|
+
if status not in (200, 400):
|
|
56
|
+
raise UnexpectedStatusCodeError(
|
|
57
|
+
f"Unexpected status code ({status})",
|
|
58
|
+
details={"status_code": status, "raw_body": body.decode("utf-8", "replace")},
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
result = json.loads(body)
|
|
63
|
+
except json.JSONDecodeError as e:
|
|
64
|
+
raise JsonParseError(
|
|
65
|
+
str(e),
|
|
66
|
+
details={"status_code": status, "raw_body": body.decode("utf-8", "replace"), "original_exception": e},
|
|
67
|
+
) from e
|
|
68
|
+
|
|
69
|
+
if status == 400:
|
|
70
|
+
code, message, details = "WFN_BAD_REQUEST_ERROR", "Bad request", {"body": result}
|
|
71
|
+
if (
|
|
72
|
+
isinstance(result, list) and len(result) == 3
|
|
73
|
+
and isinstance(result[0], str) and isinstance(result[1], str)
|
|
74
|
+
):
|
|
75
|
+
code, message, details = result
|
|
76
|
+
raise BadRequestError(message, code=code, details=details)
|
|
77
|
+
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def execute_sync(http: httpx.Client, url: str, *, bearer_auth: Optional[str] = None,
|
|
82
|
+
version: Optional[str] = None, args: Any = None) -> Any:
|
|
83
|
+
headers = build_headers(bearer_auth, version)
|
|
84
|
+
response = http.post(url, headers=headers, content=dumps(args if args is not None else {}))
|
|
85
|
+
return parse_response(response.status_code, response.content)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
async def execute_async(http: httpx.AsyncClient, url: str, *, bearer_auth: Optional[str] = None,
|
|
89
|
+
version: Optional[str] = None, args: Any = None) -> Any:
|
|
90
|
+
headers = build_headers(bearer_auth, version)
|
|
91
|
+
response = await http.post(url, headers=headers, content=dumps(args if args is not None else {}))
|
|
92
|
+
return parse_response(response.status_code, response.content)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_body_sync(http: httpx.Client, url: str, *, extra_query_params: Optional[dict] = None) -> bytes:
|
|
96
|
+
params = {k: v for k, v in (extra_query_params or {}).items() if v is not None}
|
|
97
|
+
headers = {"User-Agent": f"webfunction/{VERSION}", "Accept-Encoding": "gzip"}
|
|
98
|
+
response = http.get(url, headers=headers, params=params)
|
|
99
|
+
return response.content
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
async def get_body_async(http: httpx.AsyncClient, url: str, *, extra_query_params: Optional[dict] = None) -> bytes:
|
|
103
|
+
params = {k: v for k, v in (extra_query_params or {}).items() if v is not None}
|
|
104
|
+
headers = {"User-Agent": f"webfunction/{VERSION}", "Accept-Encoding": "gzip"}
|
|
105
|
+
response = await http.get(url, headers=headers, params=params)
|
|
106
|
+
return response.content
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION = "0.1.0"
|