# Presto! Requests
An object-oriented REST API client & requests extesion library.
As of version 1.0.0, this library can be considered stable, and significant
changes to the interface or new features are unlikely to be introduced.
#### Note: This library requires Python 3.11.0rc1 or later.
## Installation
```bash
pip install presto-requests
```
```bash
poetry add presto-requests
```
#### With async support using httpx:
```bash
pip install presto-requests[async]
```
```bash
poetry add presto-requests --extras async
```
### Concept:
Presto! Requests is a library that extends the functionality of the requests library.
It provides a simple way to create a REST API client that is object-oriented and easy to use.
### Example:
```python
from presto import Presto
import pprint
github = Presto("https://api.github.com")
user = github.users.sitbon()() # == github.users["sitbon"]().attr
print(f"User {user.login} has {user.public_repos} public repositories.")
pprint.pprint(dict(user))
```
```shell
User sitbon has 15 public repositories.
{'avatar_url': 'https://avatars.githubusercontent.com/u/1381063?v=4',
'bio': None,
'blog': '',
'company': None,
'created_at': '2012-01-26T04:25:21Z',
'email': None,
'events_url': 'https://api.github.com/users/sitbon/events{/privacy}',
'followers': 7,
'followers_url': 'https://api.github.com/users/sitbon/followers',
'following': 13,
'following_url': 'https://api.github.com/users/sitbon/following{/other_user}',
'gists_url': 'https://api.github.com/users/sitbon/gists{/gist_id}',
'gravatar_id': '',
'hireable': None,
'html_url': 'https://github.com/sitbon',
'id': 1381063,
'location': 'Portland, OR, USA',
'login': 'sitbon',
'name': 'Phillip Sitbon',
'node_id': 'MDQ6VXNlcjEzODEwNjM=',
'organizations_url': 'https://api.github.com/users/sitbon/orgs',
'public_gists': 4,
'public_repos': 15,
'received_events_url': 'https://api.github.com/users/sitbon/received_events',
'repos_url': 'https://api.github.com/users/sitbon/repos',
'site_admin': False,
'starred_url': 'https://api.github.com/users/sitbon/starred{/owner}{/repo}',
'subscriptions_url': 'https://api.github.com/users/sitbon/subscriptions',
'twitter_username': None,
'type': 'User',
'updated_at': '2022-11-22T00:41:18Z',
'url': 'https://api.github.com/users/sitbon'}
```
### Usage:
Adding to a request path is as simple as accessing an attribute of the same name
from a `Presto` instance. For example, `Presto("http://example.com").some_path`
maps to a request object that defines a GET request to `http://example.com/some_path`.
Parameters such as headers are set by calling dotted objects under `Presto`, e.g. `presto.some_path(x=y)`.
These parameters are eventually passed to requests.request() as keyword arguments, but only
at a later time when the request is executed by calling the object without any arguments.
The return value from a parameter-setting call is the object itself, to enable further chaining.
Thus, request parameters can be set and inherited by further dotted paths.
Indexing the object like a list is a convient way to extend the path to a new object for things
like id paths, e.g. `Presto("http://<base>").note[1]` maps to a request for `http://<base>/note/1`
and calling that object executes the request.
There are a few special top-level attributes that can be used to modify the request without
needing to call the object and set the `method=` parameter:
`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`, and finally `R` which is
a request object with no path and no parameters set.
#### Example:
```python
from presto import Presto
presto = Presto(url="http://127.0.0.1:8000", APPEND_SLASH=True)
print("presto:", presto)
api = presto.api
print("api:", api)
note = api(headers={"X-User": "Testing"}).note
print("api.note:", api.note, "equal:", api.note == note)
resp = api.note[4]()
print("headers:", resp.request.headers)
print("response:", resp)
print("note:", resp.attr)
```
```shell
presto: Presto(url='http://127.0.0.1:8000/', params=adict(method='GET', headers={'Accept': 'application/json'}))
api: Request(url='http://127.0.0.1:8000/api/', params=adict(method='GET', headers={'Accept': 'application/json'}))
api.note: Request(url='http://127.0.0.1:8000/api/note/', params=adict(method='GET', headers={'Accept': 'application/json', 'X-User': 'Testing'})) equal: True
headers: {'User-Agent': 'python-requests/2.28.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'Connection': 'keep-alive', 'X-User': 'Testing'}
response: <Response [200]>
note: adict(user='', id=4, url='http://127.0.0.1:8000/api/note/4/', time='2022-12-02T19:26:09-0800', note='Hello from the API!!', collection={'id': 3, 'url': 'http://127.0.0.1:8000/api/note/coll/3/', 'name': 'Public', 'public': True, 'notes': 1})
```
`response.attr` is an `adict` instance, which is a dictionary that can be accessed as attributes.
It contains the JSON-decoded content of a response, if any.
`APPEND_SLASH` is meant to be client implementation-specific, e.g. for a Django Rest Framework client, one would
typically set `Presto.APPEND_SLASH = True` or inherit from `Presto` in a pre-defined API client class.
# Async Support
Version 1.0.0 adds support for async requests using the `httpx` library.
The usage is the same as the synchronous version except when it comes to executing requests, so
calls to request objects without parameters need to be awaited. See the example below.
```python
import asyncio
from presto.asynco import AsyncPresto as Presto
async def main():
presto = Presto(url="http://127.0.0.1:8000", APPEND_SLASH=True)
print("presto:", presto)
api = presto.api
print("api:", api)
note = api(headers={"X-User": "Testing"}).note
print("api.note:", api.note, "equal:", api.note == note)
resp = await api.note[4]()
print("headers:", resp.request.headers)
print("response:", resp)
print("note:", resp.attr)
if __name__ == "__main__":
asyncio.run(main())
```
```shell
presto: AsyncPresto(url='http://127.0.0.1:8000/', params=adict(method='GET', headers={'Accept': 'application/json'}))
api: Request(url='http://127.0.0.1:8000/api/', params=adict(method='GET', headers={'Accept': 'application/json'}))
api.note: Request(url='http://127.0.0.1:8000/api/note/', params=adict(method='GET', headers={'Accept': 'application/json', 'X-User': 'Testing'})) equal: True
headers: Headers({'host': '127.0.0.1:8000', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'user-agent': 'python-httpx/0.23.1', 'accept': 'application/json', 'x-user': 'Testing'})
response: <Response [200 OK]>
note: adict(user='', id=4, url='http://127.0.0.1:8000/api/note/4/', time='2022-12-02T19:26:09-0800', note='Hello from the API!!', collection={'id': 3, 'url': 'http://127.0.0.1:8000/api/note/coll/3/', 'name': 'Public', 'public': True, 'notes': 1})
```
Raw data
{
"_id": null,
"home_page": "https://github.com/sitbon/presto",
"name": "presto-requests",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.11,<4.0",
"maintainer_email": "",
"keywords": "",
"author": "Phillip Sitbon",
"author_email": "phillip.sitbon@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/4a/d9/071f8f25e41f86351a0a3dec07c2712b7a8cad4e010f7aa6b339beea3e52/presto_requests-1.3.6.tar.gz",
"platform": null,
"description": "# Presto! Requests\n\nAn object-oriented REST API client & requests extesion library.\n\nAs of version 1.0.0, this library can be considered stable, and significant\nchanges to the interface or new features are unlikely to be introduced.\n\n#### Note: This library requires Python 3.11.0rc1 or later.\n\n## Installation\n\n```bash\npip install presto-requests\n```\n```bash\npoetry add presto-requests\n```\n\n#### With async support using httpx:\n```bash\npip install presto-requests[async]\n```\n```bash\npoetry add presto-requests --extras async\n```\n\n### Concept:\n\nPresto! Requests is a library that extends the functionality of the requests library.\nIt provides a simple way to create a REST API client that is object-oriented and easy to use.\n\n### Example:\n\n```python\nfrom presto import Presto\nimport pprint\n\ngithub = Presto(\"https://api.github.com\")\n\nuser = github.users.sitbon()() # == github.users[\"sitbon\"]().attr\n\nprint(f\"User {user.login} has {user.public_repos} public repositories.\")\n\npprint.pprint(dict(user))\n```\n```shell\nUser sitbon has 15 public repositories.\n{'avatar_url': 'https://avatars.githubusercontent.com/u/1381063?v=4',\n 'bio': None,\n 'blog': '',\n 'company': None,\n 'created_at': '2012-01-26T04:25:21Z',\n 'email': None,\n 'events_url': 'https://api.github.com/users/sitbon/events{/privacy}',\n 'followers': 7,\n 'followers_url': 'https://api.github.com/users/sitbon/followers',\n 'following': 13,\n 'following_url': 'https://api.github.com/users/sitbon/following{/other_user}',\n 'gists_url': 'https://api.github.com/users/sitbon/gists{/gist_id}',\n 'gravatar_id': '',\n 'hireable': None,\n 'html_url': 'https://github.com/sitbon',\n 'id': 1381063,\n 'location': 'Portland, OR, USA',\n 'login': 'sitbon',\n 'name': 'Phillip Sitbon',\n 'node_id': 'MDQ6VXNlcjEzODEwNjM=',\n 'organizations_url': 'https://api.github.com/users/sitbon/orgs',\n 'public_gists': 4,\n 'public_repos': 15,\n 'received_events_url': 'https://api.github.com/users/sitbon/received_events',\n 'repos_url': 'https://api.github.com/users/sitbon/repos',\n 'site_admin': False,\n 'starred_url': 'https://api.github.com/users/sitbon/starred{/owner}{/repo}',\n 'subscriptions_url': 'https://api.github.com/users/sitbon/subscriptions',\n 'twitter_username': None,\n 'type': 'User',\n 'updated_at': '2022-11-22T00:41:18Z',\n 'url': 'https://api.github.com/users/sitbon'}\n\n```\n\n### Usage:\n\nAdding to a request path is as simple as accessing an attribute of the same name\nfrom a `Presto` instance. For example, `Presto(\"http://example.com\").some_path`\nmaps to a request object that defines a GET request to `http://example.com/some_path`.\n\nParameters such as headers are set by calling dotted objects under `Presto`, e.g. `presto.some_path(x=y)`.\n\nThese parameters are eventually passed to requests.request() as keyword arguments, but only\nat a later time when the request is executed by calling the object without any arguments.\n\nThe return value from a parameter-setting call is the object itself, to enable further chaining.\nThus, request parameters can be set and inherited by further dotted paths.\n\nIndexing the object like a list is a convient way to extend the path to a new object for things\nlike id paths, e.g. `Presto(\"http://<base>\").note[1]` maps to a request for `http://<base>/note/1`\nand calling that object executes the request.\n\nThere are a few special top-level attributes that can be used to modify the request without\nneeding to call the object and set the `method=` parameter:\n`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`, and finally `R` which is\na request object with no path and no parameters set.\n\n\n#### Example:\n\n```python\nfrom presto import Presto\n\n\npresto = Presto(url=\"http://127.0.0.1:8000\", APPEND_SLASH=True)\n\nprint(\"presto:\", presto)\n\napi = presto.api\n\nprint(\"api:\", api)\n\nnote = api(headers={\"X-User\": \"Testing\"}).note\n\nprint(\"api.note:\", api.note, \"equal:\", api.note == note)\n\nresp = api.note[4]()\n\nprint(\"headers:\", resp.request.headers)\nprint(\"response:\", resp)\nprint(\"note:\", resp.attr)\n```\n```shell\npresto: Presto(url='http://127.0.0.1:8000/', params=adict(method='GET', headers={'Accept': 'application/json'}))\napi: Request(url='http://127.0.0.1:8000/api/', params=adict(method='GET', headers={'Accept': 'application/json'}))\napi.note: Request(url='http://127.0.0.1:8000/api/note/', params=adict(method='GET', headers={'Accept': 'application/json', 'X-User': 'Testing'})) equal: True\nheaders: {'User-Agent': 'python-requests/2.28.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'Connection': 'keep-alive', 'X-User': 'Testing'}\nresponse: <Response [200]>\nnote: adict(user='', id=4, url='http://127.0.0.1:8000/api/note/4/', time='2022-12-02T19:26:09-0800', note='Hello from the API!!', collection={'id': 3, 'url': 'http://127.0.0.1:8000/api/note/coll/3/', 'name': 'Public', 'public': True, 'notes': 1})\n```\n\n`response.attr` is an `adict` instance, which is a dictionary that can be accessed as attributes.\nIt contains the JSON-decoded content of a response, if any.\n\n`APPEND_SLASH` is meant to be client implementation-specific, e.g. for a Django Rest Framework client, one would\ntypically set `Presto.APPEND_SLASH = True` or inherit from `Presto` in a pre-defined API client class.\n\n# Async Support\n\nVersion 1.0.0 adds support for async requests using the `httpx` library.\n\nThe usage is the same as the synchronous version except when it comes to executing requests, so\ncalls to request objects without parameters need to be awaited. See the example below.\n\n```python\nimport asyncio\nfrom presto.asynco import AsyncPresto as Presto\n\n\nasync def main():\n presto = Presto(url=\"http://127.0.0.1:8000\", APPEND_SLASH=True)\n\n print(\"presto:\", presto)\n\n api = presto.api\n\n print(\"api:\", api)\n\n note = api(headers={\"X-User\": \"Testing\"}).note\n\n print(\"api.note:\", api.note, \"equal:\", api.note == note)\n\n resp = await api.note[4]()\n\n print(\"headers:\", resp.request.headers)\n print(\"response:\", resp)\n print(\"note:\", resp.attr)\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n```shell\npresto: AsyncPresto(url='http://127.0.0.1:8000/', params=adict(method='GET', headers={'Accept': 'application/json'}))\napi: Request(url='http://127.0.0.1:8000/api/', params=adict(method='GET', headers={'Accept': 'application/json'}))\napi.note: Request(url='http://127.0.0.1:8000/api/note/', params=adict(method='GET', headers={'Accept': 'application/json', 'X-User': 'Testing'})) equal: True\nheaders: Headers({'host': '127.0.0.1:8000', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'user-agent': 'python-httpx/0.23.1', 'accept': 'application/json', 'x-user': 'Testing'})\nresponse: <Response [200 OK]>\nnote: adict(user='', id=4, url='http://127.0.0.1:8000/api/note/4/', time='2022-12-02T19:26:09-0800', note='Hello from the API!!', collection={'id': 3, 'url': 'http://127.0.0.1:8000/api/note/coll/3/', 'name': 'Public', 'public': True, 'notes': 1})\n```",
"bugtrack_url": null,
"license": "AGPLv3",
"summary": "A modern object-oriented HTTP REST client.",
"version": "1.3.6",
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5114221fed9d72e74008ccad5363bb0e2e84ce445dd50cdebb6a5a7883b326bc",
"md5": "73ea3325be38ea41492ad47c92fafaf4",
"sha256": "4058709f65ecf615d7ca0a5b0eae581dee472c056491fc0e61df0851fd2716e4"
},
"downloads": -1,
"filename": "presto_requests-1.3.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "73ea3325be38ea41492ad47c92fafaf4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11,<4.0",
"size": 8809,
"upload_time": "2023-03-11T02:10:33",
"upload_time_iso_8601": "2023-03-11T02:10:33.609918Z",
"url": "https://files.pythonhosted.org/packages/51/14/221fed9d72e74008ccad5363bb0e2e84ce445dd50cdebb6a5a7883b326bc/presto_requests-1.3.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "4ad9071f8f25e41f86351a0a3dec07c2712b7a8cad4e010f7aa6b339beea3e52",
"md5": "b3a06dfc39e61569f3f70bc2d9f53f3e",
"sha256": "7affc71bc21fed5cb70d4077aa74d794901737683b8395d2b47cb4cc201c4e7a"
},
"downloads": -1,
"filename": "presto_requests-1.3.6.tar.gz",
"has_sig": false,
"md5_digest": "b3a06dfc39e61569f3f70bc2d9f53f3e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11,<4.0",
"size": 10391,
"upload_time": "2023-03-11T02:10:35",
"upload_time_iso_8601": "2023-03-11T02:10:35.303938Z",
"url": "https://files.pythonhosted.org/packages/4a/d9/071f8f25e41f86351a0a3dec07c2712b7a8cad4e010f7aa6b339beea3e52/presto_requests-1.3.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-03-11 02:10:35",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "sitbon",
"github_project": "presto",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "presto-requests"
}