reserp 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.
@@ -0,0 +1,45 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ name: Python ${{ matrix.python-version }}
14
+ runs-on: ubuntu-latest
15
+ timeout-minutes: 10
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+ cache: pip
26
+ - run: python -m pip install --upgrade pip
27
+ - run: python -m pip install -e ".[dev]"
28
+ - run: pytest
29
+
30
+ quality:
31
+ runs-on: ubuntu-latest
32
+ timeout-minutes: 10
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: actions/setup-python@v5
36
+ with:
37
+ python-version: "3.14"
38
+ cache: pip
39
+ - run: python -m pip install --upgrade pip
40
+ - run: python -m pip install -e ".[dev]"
41
+ - run: ruff check .
42
+ - run: ruff format --check .
43
+ - run: mypy src
44
+ - run: python -m build
45
+ - run: twine check dist/*
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .coverage
5
+ .mypy_cache/
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .venv/
9
+ build/
10
+ dist/
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.1.0] - 2026-08-18
6
+
7
+ - Initial synchronous and asynchronous Python SDK.
8
+ - Typed search responses and API errors.
9
+ - One-based pagination and raw Google Search URL support.
10
+ - Billing-safe retries and configurable timeouts.
11
+
12
+ [0.1.0]: https://github.com/reserp-ai/reserp-python/releases/tag/v0.1.0
@@ -0,0 +1,25 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve the Reserp Python SDK.
4
+
5
+ ## Development
6
+
7
+ ```bash
8
+ python -m venv .venv
9
+ source .venv/bin/activate
10
+ python -m pip install --upgrade pip
11
+ python -m pip install -e ".[dev]"
12
+ ```
13
+
14
+ Run the validation suite before opening a pull request:
15
+
16
+ ```bash
17
+ ruff check .
18
+ ruff format --check .
19
+ mypy src
20
+ pytest
21
+ python -m build
22
+ twine check dist/*
23
+ ```
24
+
25
+ Keep changes focused on the public SDK and documented API contract. Do not include API keys, account data, or private implementation details.
reserp-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Reserp
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.
reserp-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: reserp
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Reserp Google Search API
5
+ Project-URL: Homepage, https://reserp.ai
6
+ Project-URL: Documentation, https://reserp.ai/docs
7
+ Project-URL: Repository, https://github.com/reserp-ai/reserp-python
8
+ Project-URL: Issues, https://github.com/reserp-ai/reserp-python/issues
9
+ Project-URL: Changelog, https://github.com/reserp-ai/reserp-python/blob/main/CHANGELOG.md
10
+ Author-email: Reserp <no-reply@reserp.ai>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: api-client,google-search,google-search-api,python,reserp,sdk,search-api,serp,serp-api
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Internet :: WWW/HTTP
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
28
+ Requires-Dist: httpx<1,>=0.27
29
+ Provides-Extra: dev
30
+ Requires-Dist: build<2,>=1.2; extra == 'dev'
31
+ Requires-Dist: mypy<2,>=1.13; extra == 'dev'
32
+ Requires-Dist: pytest<10,>=8.3; extra == 'dev'
33
+ Requires-Dist: ruff<1,>=0.8; extra == 'dev'
34
+ Requires-Dist: twine<7,>=5.1; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ <p align="center">
38
+ <a href="https://reserp.ai">
39
+ <img src="https://reserp.ai/icon-512.png" alt="Reserp Google Search API" width="112" height="112">
40
+ </a>
41
+ </p>
42
+
43
+ # Reserp Python SDK
44
+
45
+ [![PyPI version](https://img.shields.io/pypi/v/reserp.svg)](https://pypi.org/project/reserp/)
46
+ [![Python versions](https://img.shields.io/pypi/pyversions/reserp.svg)](https://pypi.org/project/reserp/)
47
+ [![CI](https://github.com/reserp-ai/reserp-python/actions/workflows/ci.yml/badge.svg)](https://github.com/reserp-ai/reserp-python/actions/workflows/ci.yml)
48
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
49
+
50
+ The official Python SDK for [Reserp](https://reserp.ai), a Google Search API for developers and AI agents.
51
+
52
+ Retrieve structured Google Search results through one stable JSON schema. Start for free with no credit card required.
53
+
54
+ [Website](https://reserp.ai) · [API documentation](https://reserp.ai/docs) · [OpenAPI 3.1](https://reserp.ai/openapi.json) · [Pricing](https://reserp.ai/pricing)
55
+
56
+ ## Features
57
+
58
+ - Synchronous and asynchronous clients built on HTTPX.
59
+ - Typed responses that preserve the complete API response dictionary.
60
+ - One-based pagination plus support for authoritative pagination URLs.
61
+ - Configurable retries and timeouts.
62
+ - Automatic retries only when the API says the request is retryable and was not billed.
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ pip install reserp
68
+ ```
69
+
70
+ Python 3.10 or later is required.
71
+
72
+ ## Quick start
73
+
74
+ ```python
75
+ import os
76
+
77
+ from reserp import Reserp
78
+
79
+ client = Reserp(api_key=os.environ["RESERP_API_KEY"])
80
+
81
+ response = client.search(
82
+ query="best pizza in dubai",
83
+ gl="ae",
84
+ hl="en",
85
+ )
86
+
87
+ for result in response["results"]:
88
+ print(result.get("text"), result.get("url"))
89
+ ```
90
+
91
+ Create an API key in the [Reserp dashboard](https://reserp.ai/dashboard). Keep API keys on your server; never embed one in browser or mobile code.
92
+
93
+ The SDK returns the API response as a normal Python dictionary. Result order, nested `children`, pagination, and billing fields remain intact.
94
+
95
+ ## Async client
96
+
97
+ ```python
98
+ import asyncio
99
+ import os
100
+
101
+ from reserp import AsyncReserp
102
+
103
+
104
+ async def main() -> None:
105
+ async with AsyncReserp(api_key=os.environ["RESERP_API_KEY"]) as client:
106
+ response = await client.search(
107
+ query="semiconductor manufacturing",
108
+ gl="us",
109
+ hl="en",
110
+ )
111
+ print(response["results"])
112
+
113
+
114
+ asyncio.run(main())
115
+ ```
116
+
117
+ The synchronous client is also a context manager:
118
+
119
+ ```python
120
+ with Reserp(api_key=os.environ["RESERP_API_KEY"]) as client:
121
+ response = client.search(query="photonic computing")
122
+ ```
123
+
124
+ ## Pagination
125
+
126
+ `page` is one-based, so you do not need to calculate Google's `start` offsets:
127
+
128
+ ```python
129
+ second_page = client.search(
130
+ query="photonic computing",
131
+ page=2,
132
+ )
133
+ ```
134
+
135
+ You can also follow the authoritative pagination URL returned by the API:
136
+
137
+ ```python
138
+ first = client.search(query="photonic computing")
139
+ second = client.next_page(first)
140
+ ```
141
+
142
+ Do not derive pagination from `len(response["results"])`. A response can contain organic listings, news, carousels, sitelinks, and nested result blocks.
143
+
144
+ ## Google parameters
145
+
146
+ Use `params` for additional Google parameters such as `tbs` and `tbm`:
147
+
148
+ ```python
149
+ news = client.search(
150
+ query="semiconductor manufacturing",
151
+ params={"tbm": "nws", "tbs": "qdr:w"},
152
+ )
153
+ ```
154
+
155
+ For complete control, submit a full Google Search URL:
156
+
157
+ ```python
158
+ response = client.search_url(
159
+ "https://www.google.com/search?q=semiconductor+manufacturing&gl=us&hl=en&tbs=qdr:w"
160
+ )
161
+ ```
162
+
163
+ All Google URL parameters pass through unchanged except parameters documented as unsupported by Reserp. The `num` parameter is currently unsupported.
164
+
165
+ ## Errors and retries
166
+
167
+ API failures raise `ReserpAPIError` with the stable public error code and billing state:
168
+
169
+ ```python
170
+ from reserp import ReserpAPIError
171
+
172
+ try:
173
+ response = client.search(query="photonic computing")
174
+ except ReserpAPIError as error:
175
+ print(error.status, error.code, error.retryable, error.billed)
176
+ ```
177
+
178
+ The SDK retries retryable API responses up to two times by default, respecting `Retry-After` for rate limits. It never automatically retries a response whose `billed` field is true. Network failures are not automatically retried because the client cannot know whether the original request reached the API.
179
+
180
+ Configure retries and per-attempt timeouts globally or per request:
181
+
182
+ ```python
183
+ client = Reserp(
184
+ api_key=os.environ["RESERP_API_KEY"],
185
+ max_retries=1,
186
+ timeout=20.0,
187
+ )
188
+
189
+ response = client.search(
190
+ query="photonic computing",
191
+ max_retries=0,
192
+ timeout=10.0,
193
+ )
194
+ ```
195
+
196
+ Set `timeout=0` to disable the SDK timeout.
197
+
198
+ ## API reference
199
+
200
+ - [Reserp API documentation](https://reserp.ai/docs)
201
+ - [OpenAPI 3.1 document](https://reserp.ai/openapi.json)
202
+ - [Pricing](https://reserp.ai/pricing)
203
+
204
+ ## License
205
+
206
+ MIT
reserp-0.1.0/README.md ADDED
@@ -0,0 +1,170 @@
1
+ <p align="center">
2
+ <a href="https://reserp.ai">
3
+ <img src="https://reserp.ai/icon-512.png" alt="Reserp Google Search API" width="112" height="112">
4
+ </a>
5
+ </p>
6
+
7
+ # Reserp Python SDK
8
+
9
+ [![PyPI version](https://img.shields.io/pypi/v/reserp.svg)](https://pypi.org/project/reserp/)
10
+ [![Python versions](https://img.shields.io/pypi/pyversions/reserp.svg)](https://pypi.org/project/reserp/)
11
+ [![CI](https://github.com/reserp-ai/reserp-python/actions/workflows/ci.yml/badge.svg)](https://github.com/reserp-ai/reserp-python/actions/workflows/ci.yml)
12
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
13
+
14
+ The official Python SDK for [Reserp](https://reserp.ai), a Google Search API for developers and AI agents.
15
+
16
+ Retrieve structured Google Search results through one stable JSON schema. Start for free with no credit card required.
17
+
18
+ [Website](https://reserp.ai) · [API documentation](https://reserp.ai/docs) · [OpenAPI 3.1](https://reserp.ai/openapi.json) · [Pricing](https://reserp.ai/pricing)
19
+
20
+ ## Features
21
+
22
+ - Synchronous and asynchronous clients built on HTTPX.
23
+ - Typed responses that preserve the complete API response dictionary.
24
+ - One-based pagination plus support for authoritative pagination URLs.
25
+ - Configurable retries and timeouts.
26
+ - Automatic retries only when the API says the request is retryable and was not billed.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install reserp
32
+ ```
33
+
34
+ Python 3.10 or later is required.
35
+
36
+ ## Quick start
37
+
38
+ ```python
39
+ import os
40
+
41
+ from reserp import Reserp
42
+
43
+ client = Reserp(api_key=os.environ["RESERP_API_KEY"])
44
+
45
+ response = client.search(
46
+ query="best pizza in dubai",
47
+ gl="ae",
48
+ hl="en",
49
+ )
50
+
51
+ for result in response["results"]:
52
+ print(result.get("text"), result.get("url"))
53
+ ```
54
+
55
+ Create an API key in the [Reserp dashboard](https://reserp.ai/dashboard). Keep API keys on your server; never embed one in browser or mobile code.
56
+
57
+ The SDK returns the API response as a normal Python dictionary. Result order, nested `children`, pagination, and billing fields remain intact.
58
+
59
+ ## Async client
60
+
61
+ ```python
62
+ import asyncio
63
+ import os
64
+
65
+ from reserp import AsyncReserp
66
+
67
+
68
+ async def main() -> None:
69
+ async with AsyncReserp(api_key=os.environ["RESERP_API_KEY"]) as client:
70
+ response = await client.search(
71
+ query="semiconductor manufacturing",
72
+ gl="us",
73
+ hl="en",
74
+ )
75
+ print(response["results"])
76
+
77
+
78
+ asyncio.run(main())
79
+ ```
80
+
81
+ The synchronous client is also a context manager:
82
+
83
+ ```python
84
+ with Reserp(api_key=os.environ["RESERP_API_KEY"]) as client:
85
+ response = client.search(query="photonic computing")
86
+ ```
87
+
88
+ ## Pagination
89
+
90
+ `page` is one-based, so you do not need to calculate Google's `start` offsets:
91
+
92
+ ```python
93
+ second_page = client.search(
94
+ query="photonic computing",
95
+ page=2,
96
+ )
97
+ ```
98
+
99
+ You can also follow the authoritative pagination URL returned by the API:
100
+
101
+ ```python
102
+ first = client.search(query="photonic computing")
103
+ second = client.next_page(first)
104
+ ```
105
+
106
+ Do not derive pagination from `len(response["results"])`. A response can contain organic listings, news, carousels, sitelinks, and nested result blocks.
107
+
108
+ ## Google parameters
109
+
110
+ Use `params` for additional Google parameters such as `tbs` and `tbm`:
111
+
112
+ ```python
113
+ news = client.search(
114
+ query="semiconductor manufacturing",
115
+ params={"tbm": "nws", "tbs": "qdr:w"},
116
+ )
117
+ ```
118
+
119
+ For complete control, submit a full Google Search URL:
120
+
121
+ ```python
122
+ response = client.search_url(
123
+ "https://www.google.com/search?q=semiconductor+manufacturing&gl=us&hl=en&tbs=qdr:w"
124
+ )
125
+ ```
126
+
127
+ All Google URL parameters pass through unchanged except parameters documented as unsupported by Reserp. The `num` parameter is currently unsupported.
128
+
129
+ ## Errors and retries
130
+
131
+ API failures raise `ReserpAPIError` with the stable public error code and billing state:
132
+
133
+ ```python
134
+ from reserp import ReserpAPIError
135
+
136
+ try:
137
+ response = client.search(query="photonic computing")
138
+ except ReserpAPIError as error:
139
+ print(error.status, error.code, error.retryable, error.billed)
140
+ ```
141
+
142
+ The SDK retries retryable API responses up to two times by default, respecting `Retry-After` for rate limits. It never automatically retries a response whose `billed` field is true. Network failures are not automatically retried because the client cannot know whether the original request reached the API.
143
+
144
+ Configure retries and per-attempt timeouts globally or per request:
145
+
146
+ ```python
147
+ client = Reserp(
148
+ api_key=os.environ["RESERP_API_KEY"],
149
+ max_retries=1,
150
+ timeout=20.0,
151
+ )
152
+
153
+ response = client.search(
154
+ query="photonic computing",
155
+ max_retries=0,
156
+ timeout=10.0,
157
+ )
158
+ ```
159
+
160
+ Set `timeout=0` to disable the SDK timeout.
161
+
162
+ ## API reference
163
+
164
+ - [Reserp API documentation](https://reserp.ai/docs)
165
+ - [OpenAPI 3.1 document](https://reserp.ai/openapi.json)
166
+ - [Pricing](https://reserp.ai/pricing)
167
+
168
+ ## License
169
+
170
+ MIT
@@ -0,0 +1,5 @@
1
+ # Security
2
+
3
+ Do not include API keys or account data in issues, discussions, logs, or example code.
4
+
5
+ To report a vulnerability privately, use [GitHub private vulnerability reporting](https://github.com/reserp-ai/reserp-python/security/advisories/new).
@@ -0,0 +1,83 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27,<1.32"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "reserp"
7
+ dynamic = ["version"]
8
+ description = "Official Python SDK for the Reserp Google Search API"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Reserp", email = "no-reply@reserp.ai" }]
14
+ keywords = [
15
+ "reserp",
16
+ "google-search",
17
+ "google-search-api",
18
+ "serp",
19
+ "serp-api",
20
+ "search-api",
21
+ "api-client",
22
+ "sdk",
23
+ "python",
24
+ ]
25
+ classifiers = [
26
+ "Development Status :: 4 - Beta",
27
+ "Intended Audience :: Developers",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3 :: Only",
31
+ "Programming Language :: Python :: 3.10",
32
+ "Programming Language :: Python :: 3.11",
33
+ "Programming Language :: Python :: 3.12",
34
+ "Programming Language :: Python :: 3.13",
35
+ "Programming Language :: Python :: 3.14",
36
+ "Topic :: Internet :: WWW/HTTP",
37
+ "Topic :: Software Development :: Libraries :: Python Modules",
38
+ "Typing :: Typed",
39
+ ]
40
+ dependencies = ["httpx>=0.27,<1"]
41
+
42
+ [project.optional-dependencies]
43
+ dev = [
44
+ "build>=1.2,<2",
45
+ "mypy>=1.13,<2",
46
+ "pytest>=8.3,<10",
47
+ "ruff>=0.8,<1",
48
+ "twine>=5.1,<7",
49
+ ]
50
+
51
+ [project.urls]
52
+ Homepage = "https://reserp.ai"
53
+ Documentation = "https://reserp.ai/docs"
54
+ Repository = "https://github.com/reserp-ai/reserp-python"
55
+ Issues = "https://github.com/reserp-ai/reserp-python/issues"
56
+ Changelog = "https://github.com/reserp-ai/reserp-python/blob/main/CHANGELOG.md"
57
+
58
+ [tool.hatch.version]
59
+ path = "src/reserp/__about__.py"
60
+
61
+ [tool.hatch.build.targets.wheel]
62
+ packages = ["src/reserp"]
63
+
64
+ [tool.ruff]
65
+ target-version = "py310"
66
+ line-length = 100
67
+ src = ["src", "tests"]
68
+
69
+ [tool.ruff.lint]
70
+ select = ["B", "E", "F", "I", "RUF", "SIM", "UP"]
71
+
72
+ [tool.ruff.format]
73
+ quote-style = "double"
74
+
75
+ [tool.mypy]
76
+ python_version = "3.10"
77
+ strict = true
78
+ files = ["src"]
79
+ pretty = true
80
+
81
+ [tool.pytest.ini_options]
82
+ addopts = "-q"
83
+ testpaths = ["tests"]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,37 @@
1
+ from .__about__ import __version__
2
+ from .client import AsyncReserp, Reserp
3
+ from .errors import (
4
+ ReserpAPIError,
5
+ ReserpConnectionError,
6
+ ReserpError,
7
+ ReserpTimeoutError,
8
+ ReserpUnexpectedResponseError,
9
+ )
10
+ from .types import (
11
+ ErrorCode,
12
+ ErrorResponse,
13
+ GoogleParameterValue,
14
+ Pagination,
15
+ Result,
16
+ SearchResponse,
17
+ )
18
+ from .urls import build_google_search_url, validate_google_search_url
19
+
20
+ __all__ = [
21
+ "AsyncReserp",
22
+ "ErrorCode",
23
+ "ErrorResponse",
24
+ "GoogleParameterValue",
25
+ "Pagination",
26
+ "Reserp",
27
+ "ReserpAPIError",
28
+ "ReserpConnectionError",
29
+ "ReserpError",
30
+ "ReserpTimeoutError",
31
+ "ReserpUnexpectedResponseError",
32
+ "Result",
33
+ "SearchResponse",
34
+ "__version__",
35
+ "build_google_search_url",
36
+ "validate_google_search_url",
37
+ ]