hirebase 0.1.1__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.
- hirebase-0.1.1/LICENSE +8 -0
- hirebase-0.1.1/PKG-INFO +289 -0
- hirebase-0.1.1/README.md +250 -0
- hirebase-0.1.1/pyproject.toml +74 -0
- hirebase-0.1.1/setup.cfg +4 -0
- hirebase-0.1.1/src/hirebase/__init__.py +102 -0
- hirebase-0.1.1/src/hirebase/_files.py +53 -0
- hirebase-0.1.1/src/hirebase/_ops.py +377 -0
- hirebase-0.1.1/src/hirebase/_version.py +1 -0
- hirebase-0.1.1/src/hirebase/client.py +227 -0
- hirebase-0.1.1/src/hirebase/config.py +72 -0
- hirebase-0.1.1/src/hirebase/exceptions.py +123 -0
- hirebase-0.1.1/src/hirebase/models/__init__.py +50 -0
- hirebase-0.1.1/src/hirebase/models/base.py +45 -0
- hirebase-0.1.1/src/hirebase/models/common.py +47 -0
- hirebase-0.1.1/src/hirebase/models/companies.py +176 -0
- hirebase-0.1.1/src/hirebase/models/insights.py +84 -0
- hirebase-0.1.1/src/hirebase/models/jobs.py +202 -0
- hirebase-0.1.1/src/hirebase/models/neural.py +179 -0
- hirebase-0.1.1/src/hirebase/models/resumes.py +47 -0
- hirebase-0.1.1/src/hirebase/models/tasks.py +69 -0
- hirebase-0.1.1/src/hirebase/py.typed +0 -0
- hirebase-0.1.1/src/hirebase/resources/__init__.py +18 -0
- hirebase-0.1.1/src/hirebase/resources/companies.py +180 -0
- hirebase-0.1.1/src/hirebase/resources/jobs.py +233 -0
- hirebase-0.1.1/src/hirebase/resources/resumes.py +123 -0
- hirebase-0.1.1/src/hirebase/resources/tasks.py +99 -0
- hirebase-0.1.1/src/hirebase/streaming.py +147 -0
- hirebase-0.1.1/src/hirebase.egg-info/PKG-INFO +289 -0
- hirebase-0.1.1/src/hirebase.egg-info/SOURCES.txt +53 -0
- hirebase-0.1.1/src/hirebase.egg-info/dependency_links.txt +1 -0
- hirebase-0.1.1/src/hirebase.egg-info/entry_points.txt +2 -0
- hirebase-0.1.1/src/hirebase.egg-info/requires.txt +18 -0
- hirebase-0.1.1/src/hirebase.egg-info/top_level.txt +2 -0
- hirebase-0.1.1/src/hirebase_cli/__init__.py +3 -0
- hirebase-0.1.1/src/hirebase_cli/client.py +476 -0
- hirebase-0.1.1/src/hirebase_cli/commands/__init__.py +10 -0
- hirebase-0.1.1/src/hirebase_cli/commands/blog.py +357 -0
- hirebase-0.1.1/src/hirebase_cli/commands/companies.py +222 -0
- hirebase-0.1.1/src/hirebase_cli/commands/health.py +39 -0
- hirebase-0.1.1/src/hirebase_cli/commands/insights.py +363 -0
- hirebase-0.1.1/src/hirebase_cli/commands/jobs.py +355 -0
- hirebase-0.1.1/src/hirebase_cli/commands/scraper.py +126 -0
- hirebase-0.1.1/src/hirebase_cli/config.py +54 -0
- hirebase-0.1.1/src/hirebase_cli/formatters.py +707 -0
- hirebase-0.1.1/src/hirebase_cli/main.py +142 -0
- hirebase-0.1.1/src/hirebase_cli/models.py +223 -0
- hirebase-0.1.1/tests/test_client_mock.py +155 -0
- hirebase-0.1.1/tests/test_integration.py +76 -0
- hirebase-0.1.1/tests/test_neural.py +88 -0
- hirebase-0.1.1/tests/test_parsing.py +100 -0
- hirebase-0.1.1/tests/test_query.py +67 -0
- hirebase-0.1.1/tests/test_resume_model.py +27 -0
- hirebase-0.1.1/tests/test_resumes_mock.py +81 -0
- hirebase-0.1.1/tests/test_streaming.py +42 -0
hirebase-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Copyright 2026 Hirebase LLC
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
8
|
+
|
hirebase-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hirebase
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Official Python SDK for the Hirebase API (jobs & company data)
|
|
5
|
+
Author-email: Hirebase <spencer@hirebase.org>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://hirebase.org
|
|
8
|
+
Project-URL: Documentation, https://docs.hirebase.org
|
|
9
|
+
Project-URL: Repository, https://github.com/hirebase/hirebase-python-sdk
|
|
10
|
+
Keywords: hirebase,jobs,hiring,api,sdk,company data
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: requests>=2.28.0
|
|
24
|
+
Requires-Dist: httpx>=0.25.0
|
|
25
|
+
Requires-Dist: pydantic>=2.0.0
|
|
26
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
27
|
+
Provides-Extra: streaming
|
|
28
|
+
Requires-Dist: ijson>=3.2.0; extra == "streaming"
|
|
29
|
+
Provides-Extra: cli
|
|
30
|
+
Requires-Dist: typer>=0.9.0; extra == "cli"
|
|
31
|
+
Requires-Dist: rich>=13.0.0; extra == "cli"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ijson>=3.2.0; extra == "dev"
|
|
36
|
+
Requires-Dist: typer>=0.9.0; extra == "dev"
|
|
37
|
+
Requires-Dist: rich>=13.0.0; extra == "dev"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
<div align="left" style="margin-bottom: 16px;">
|
|
41
|
+
<img src="https://www.hirebase.org/hirebase-logo-text.svg" alt="Hirebase Logo" width="160" style="vertical-align: middle; margin-bottom: 8px;" />
|
|
42
|
+
<div style="margin-top: 12px; display: flex; gap: 12px;">
|
|
43
|
+
<a href="https://www.hirebase.org/" style="text-decoration:none;">
|
|
44
|
+
<img src="https://img.shields.io/badge/Website-hirebase.org-blue?style=for-the-badge&logo=Google%20chrome&logoColor=white" alt="Website" />
|
|
45
|
+
</a>
|
|
46
|
+
<a href="https://app.hirebase.org/login" style="text-decoration:none;">
|
|
47
|
+
<img src="https://img.shields.io/badge/Login-Login-green?style=for-the-badge&logo=google&logoColor=white" alt="Login" />
|
|
48
|
+
</a>
|
|
49
|
+
<a href="https://app.hirebase.org/signup" style="text-decoration:none;">
|
|
50
|
+
<img src="https://img.shields.io/badge/Sign%20Up-Create%20Account-purple?style=for-the-badge&logo=addthis&logoColor=white" alt="Sign Up" />
|
|
51
|
+
</a>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div>
|
|
55
|
+
<span style="font-size:2.4rem;font-weight:600;">hirebase-python-sdk</span>
|
|
56
|
+
</div>
|
|
57
|
+
A lean, typed Python client for the [Hirebase API](https://docs.hirebase.org/) —
|
|
58
|
+
search jobs and companies, run market insights, and export job data at scale.
|
|
59
|
+
|
|
60
|
+
- **Sync and async** clients (`hirebase.Client` / `hirebase.AsyncClient`).
|
|
61
|
+
- **Typed by default** — responses come back as Pydantic models; pass
|
|
62
|
+
`return_type=dict` anywhere for raw dicts.
|
|
63
|
+
- **Streaming exports** — kick off an export, poll it, download it, and stream
|
|
64
|
+
millions of jobs without loading them into memory.
|
|
65
|
+
- **Self-contained** — the SDK ships its own types and depends only on
|
|
66
|
+
`requests`, `httpx`, and `pydantic`.
|
|
67
|
+
|
|
68
|
+
> **Guides:** [Getting started](./docs/README.md) ·
|
|
69
|
+
> [Jobs](./docs/jobs.md) · [Companies](./docs/companies.md) ·
|
|
70
|
+
> [Resumes](./docs/resumes.md) · [Tasks](./docs/tasks.md) · [Errors](./docs/errors.md) ·
|
|
71
|
+
> [Examples](./examples/README.md)
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install hirebase
|
|
77
|
+
|
|
78
|
+
# Optional extras
|
|
79
|
+
pip install "hirebase[streaming]" # ijson, for streaming JSON-array exports
|
|
80
|
+
pip install "hirebase[cli]" # the bundled `hirebase` command-line tool
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Authentication
|
|
84
|
+
|
|
85
|
+
Pass your API key directly, or set it via the environment:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import hirebase
|
|
89
|
+
client = hirebase.Client(api_key="sk_live_...")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export HIREBASE_API_KEY="sk_live_..."
|
|
94
|
+
export HIREBASE_BASE_URL="https://api.hirebase.org" # optional, this is the default
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Resolution order for every setting is **argument → environment variable →
|
|
98
|
+
default**. The base URL defaults to `https://api.hirebase.org`.
|
|
99
|
+
|
|
100
|
+
## Quickstart
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import hirebase
|
|
104
|
+
|
|
105
|
+
client = hirebase.Client(api_key="sk_live_...")
|
|
106
|
+
|
|
107
|
+
# Search jobs — results are typed and iterable
|
|
108
|
+
result = client.jobs.search({
|
|
109
|
+
"job_titles": ["Software Engineer", "Product Engineer"],
|
|
110
|
+
"locations": [{"city": "San Francisco", "region": "California",
|
|
111
|
+
"country": "United States"}],
|
|
112
|
+
"limit": 20,
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
print(result.total_count, "matches")
|
|
116
|
+
for job in result:
|
|
117
|
+
print(job.job_title, "@", job.company_name, "—", job.salary_range)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Booleans are accepted natively (`visa=True`), and `locations` is a friendly
|
|
121
|
+
alias for the API's `geo_locations`. Unknown filter keys are passed through
|
|
122
|
+
untouched, so new API features work before the SDK is updated.
|
|
123
|
+
|
|
124
|
+
### Async
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
import asyncio, hirebase
|
|
128
|
+
|
|
129
|
+
async def main():
|
|
130
|
+
async with hirebase.AsyncClient(api_key="sk_live_...") as client:
|
|
131
|
+
result = await client.jobs.search({"job_titles": ["Engineer"]})
|
|
132
|
+
for job in result:
|
|
133
|
+
print(job.job_title)
|
|
134
|
+
|
|
135
|
+
asyncio.run(main())
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Every method has the same signature on both clients — the async versions are
|
|
139
|
+
awaitable.
|
|
140
|
+
|
|
141
|
+
## Jobs
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
# Search
|
|
145
|
+
result = client.jobs.search(query, page=1, limit=20)
|
|
146
|
+
|
|
147
|
+
# Fetch one job
|
|
148
|
+
job = client.jobs.get("6958cfd211e2763c3491ef8b")
|
|
149
|
+
|
|
150
|
+
# Market insights for a cohort (same filter shape as search)
|
|
151
|
+
insights = client.jobs.insights({"job_titles": ["Data Scientist"]})
|
|
152
|
+
print(insights.headline.median_salary, insights.salary.p90)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Typed inputs
|
|
156
|
+
|
|
157
|
+
You can pass a plain `dict` or build a typed query:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from hirebase import JobQuery, SalaryRange
|
|
161
|
+
|
|
162
|
+
query = JobQuery(
|
|
163
|
+
job_titles=["Backend Engineer"],
|
|
164
|
+
salary=SalaryRange(min=150_000, currency="USD"),
|
|
165
|
+
location_types=["Remote"],
|
|
166
|
+
visa=True,
|
|
167
|
+
)
|
|
168
|
+
result = client.jobs.search(query)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Exporting jobs (async task flow)
|
|
172
|
+
|
|
173
|
+
Exports are processed server-side and returned as a downloadable file.
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
query = {
|
|
177
|
+
"job_titles": ["Software Engineer", "Product Engineer", "Fullstack Engineer"],
|
|
178
|
+
"locations": [{"city": "San Francisco", "region": "California",
|
|
179
|
+
"country": "United States"}],
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# 1. Start the export -> returns a Task
|
|
183
|
+
task = client.jobs.export(query, format="json") # or format="csv"
|
|
184
|
+
|
|
185
|
+
# 2. Poll until it finishes -> (success, result)
|
|
186
|
+
success, result = client.tasks.poll(task)
|
|
187
|
+
if not success:
|
|
188
|
+
raise RuntimeError(f"Export failed: {result.error}")
|
|
189
|
+
|
|
190
|
+
# 3. Download the file (streamed to disk)
|
|
191
|
+
client.stream_file(result["download_url"], file_path="./jobs.json")
|
|
192
|
+
|
|
193
|
+
# 4. Stream jobs from the file (typed by default; uses constant memory)
|
|
194
|
+
for job in client.jobs.stream_file("./jobs.json"):
|
|
195
|
+
print(job.job_title)
|
|
196
|
+
|
|
197
|
+
# ...or get raw dicts
|
|
198
|
+
for row in client.jobs.stream_file("./jobs.json", return_type=dict):
|
|
199
|
+
...
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`poll()` accepts a `Task`, a task dict, or a task id, plus `interval`,
|
|
203
|
+
`timeout`, and an `on_progress` callback. The result dict contains
|
|
204
|
+
`download_url`, `file_size`, `record_count`, and `expiry_time`.
|
|
205
|
+
|
|
206
|
+
You can also stream **directly from the export URL** without saving to disk
|
|
207
|
+
(JSON Lines exports only):
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
for job in client.jobs.stream_url(result["download_url"]):
|
|
211
|
+
print(job.job_title)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Companies
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# Search
|
|
218
|
+
companies = client.companies.search({"company_name": "Stripe"})
|
|
219
|
+
for company in companies:
|
|
220
|
+
print(company.company_name, company.company_slug)
|
|
221
|
+
|
|
222
|
+
# Get a company by slug — optionally with its jobs and live insights
|
|
223
|
+
company = client.companies.get("stripe", return_jobs=True, return_insights=True)
|
|
224
|
+
print(company.description_summary)
|
|
225
|
+
print(company.insights_data.headline.total_count)
|
|
226
|
+
|
|
227
|
+
# Bound helpers (the object remembers its client)
|
|
228
|
+
insights = company.insights()
|
|
229
|
+
jobs = company.get_jobs(limit=10)
|
|
230
|
+
|
|
231
|
+
# Company-scoped insights directly
|
|
232
|
+
insights = client.companies.insights("stripe", query={"days_ago": 30})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Typed vs. dict responses
|
|
236
|
+
|
|
237
|
+
Every method returns typed models by default. Pass `return_type=dict` to get
|
|
238
|
+
the raw API payload instead:
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
data = client.jobs.search(query, return_type=dict) # -> dict
|
|
242
|
+
job = client.jobs.get(job_id, return_type=dict) # -> dict
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Errors
|
|
246
|
+
|
|
247
|
+
All errors subclass `hirebase.HirebaseError`:
|
|
248
|
+
|
|
249
|
+
| Exception | Meaning |
|
|
250
|
+
|---|---|
|
|
251
|
+
| `ConfigurationError` | No API key / bad config |
|
|
252
|
+
| `AuthenticationError` | 401 — invalid API key |
|
|
253
|
+
| `PaymentRequiredError` | 402 — plan/credits required |
|
|
254
|
+
| `PermissionError_` | 403 — not allowed |
|
|
255
|
+
| `NotFoundError` | 404 |
|
|
256
|
+
| `RateLimitError` | 429 |
|
|
257
|
+
| `ServerError` | 5xx |
|
|
258
|
+
| `APIError` | any other non-2xx (`.status_code`, `.message`, `.body`) |
|
|
259
|
+
| `TaskFailed` / `TaskTimeout` | export task failed or timed out |
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
import hirebase
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
client.jobs.search(query)
|
|
266
|
+
except hirebase.RateLimitError:
|
|
267
|
+
...
|
|
268
|
+
except hirebase.APIError as e:
|
|
269
|
+
print(e.status_code, e.message)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Development
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
pip install -e ".[dev]"
|
|
276
|
+
|
|
277
|
+
# Offline unit tests (no network)
|
|
278
|
+
pytest
|
|
279
|
+
|
|
280
|
+
# Live integration tests against the real API
|
|
281
|
+
HIREBASE_API_KEY=sk_live_... pytest tests/test_integration.py -v
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
> If your environment preloads conflicting pytest plugins, run with
|
|
285
|
+
> `PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest`.
|
|
286
|
+
|
|
287
|
+
## License
|
|
288
|
+
|
|
289
|
+
MIT — see [LICENSE](LICENSE).
|
hirebase-0.1.1/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
<div align="left" style="margin-bottom: 16px;">
|
|
2
|
+
<img src="https://www.hirebase.org/hirebase-logo-text.svg" alt="Hirebase Logo" width="160" style="vertical-align: middle; margin-bottom: 8px;" />
|
|
3
|
+
<div style="margin-top: 12px; display: flex; gap: 12px;">
|
|
4
|
+
<a href="https://www.hirebase.org/" style="text-decoration:none;">
|
|
5
|
+
<img src="https://img.shields.io/badge/Website-hirebase.org-blue?style=for-the-badge&logo=Google%20chrome&logoColor=white" alt="Website" />
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://app.hirebase.org/login" style="text-decoration:none;">
|
|
8
|
+
<img src="https://img.shields.io/badge/Login-Login-green?style=for-the-badge&logo=google&logoColor=white" alt="Login" />
|
|
9
|
+
</a>
|
|
10
|
+
<a href="https://app.hirebase.org/signup" style="text-decoration:none;">
|
|
11
|
+
<img src="https://img.shields.io/badge/Sign%20Up-Create%20Account-purple?style=for-the-badge&logo=addthis&logoColor=white" alt="Sign Up" />
|
|
12
|
+
</a>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<div>
|
|
16
|
+
<span style="font-size:2.4rem;font-weight:600;">hirebase-python-sdk</span>
|
|
17
|
+
</div>
|
|
18
|
+
A lean, typed Python client for the [Hirebase API](https://docs.hirebase.org/) —
|
|
19
|
+
search jobs and companies, run market insights, and export job data at scale.
|
|
20
|
+
|
|
21
|
+
- **Sync and async** clients (`hirebase.Client` / `hirebase.AsyncClient`).
|
|
22
|
+
- **Typed by default** — responses come back as Pydantic models; pass
|
|
23
|
+
`return_type=dict` anywhere for raw dicts.
|
|
24
|
+
- **Streaming exports** — kick off an export, poll it, download it, and stream
|
|
25
|
+
millions of jobs without loading them into memory.
|
|
26
|
+
- **Self-contained** — the SDK ships its own types and depends only on
|
|
27
|
+
`requests`, `httpx`, and `pydantic`.
|
|
28
|
+
|
|
29
|
+
> **Guides:** [Getting started](./docs/README.md) ·
|
|
30
|
+
> [Jobs](./docs/jobs.md) · [Companies](./docs/companies.md) ·
|
|
31
|
+
> [Resumes](./docs/resumes.md) · [Tasks](./docs/tasks.md) · [Errors](./docs/errors.md) ·
|
|
32
|
+
> [Examples](./examples/README.md)
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install hirebase
|
|
38
|
+
|
|
39
|
+
# Optional extras
|
|
40
|
+
pip install "hirebase[streaming]" # ijson, for streaming JSON-array exports
|
|
41
|
+
pip install "hirebase[cli]" # the bundled `hirebase` command-line tool
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Authentication
|
|
45
|
+
|
|
46
|
+
Pass your API key directly, or set it via the environment:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import hirebase
|
|
50
|
+
client = hirebase.Client(api_key="sk_live_...")
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export HIREBASE_API_KEY="sk_live_..."
|
|
55
|
+
export HIREBASE_BASE_URL="https://api.hirebase.org" # optional, this is the default
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Resolution order for every setting is **argument → environment variable →
|
|
59
|
+
default**. The base URL defaults to `https://api.hirebase.org`.
|
|
60
|
+
|
|
61
|
+
## Quickstart
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import hirebase
|
|
65
|
+
|
|
66
|
+
client = hirebase.Client(api_key="sk_live_...")
|
|
67
|
+
|
|
68
|
+
# Search jobs — results are typed and iterable
|
|
69
|
+
result = client.jobs.search({
|
|
70
|
+
"job_titles": ["Software Engineer", "Product Engineer"],
|
|
71
|
+
"locations": [{"city": "San Francisco", "region": "California",
|
|
72
|
+
"country": "United States"}],
|
|
73
|
+
"limit": 20,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
print(result.total_count, "matches")
|
|
77
|
+
for job in result:
|
|
78
|
+
print(job.job_title, "@", job.company_name, "—", job.salary_range)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Booleans are accepted natively (`visa=True`), and `locations` is a friendly
|
|
82
|
+
alias for the API's `geo_locations`. Unknown filter keys are passed through
|
|
83
|
+
untouched, so new API features work before the SDK is updated.
|
|
84
|
+
|
|
85
|
+
### Async
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import asyncio, hirebase
|
|
89
|
+
|
|
90
|
+
async def main():
|
|
91
|
+
async with hirebase.AsyncClient(api_key="sk_live_...") as client:
|
|
92
|
+
result = await client.jobs.search({"job_titles": ["Engineer"]})
|
|
93
|
+
for job in result:
|
|
94
|
+
print(job.job_title)
|
|
95
|
+
|
|
96
|
+
asyncio.run(main())
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Every method has the same signature on both clients — the async versions are
|
|
100
|
+
awaitable.
|
|
101
|
+
|
|
102
|
+
## Jobs
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# Search
|
|
106
|
+
result = client.jobs.search(query, page=1, limit=20)
|
|
107
|
+
|
|
108
|
+
# Fetch one job
|
|
109
|
+
job = client.jobs.get("6958cfd211e2763c3491ef8b")
|
|
110
|
+
|
|
111
|
+
# Market insights for a cohort (same filter shape as search)
|
|
112
|
+
insights = client.jobs.insights({"job_titles": ["Data Scientist"]})
|
|
113
|
+
print(insights.headline.median_salary, insights.salary.p90)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Typed inputs
|
|
117
|
+
|
|
118
|
+
You can pass a plain `dict` or build a typed query:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from hirebase import JobQuery, SalaryRange
|
|
122
|
+
|
|
123
|
+
query = JobQuery(
|
|
124
|
+
job_titles=["Backend Engineer"],
|
|
125
|
+
salary=SalaryRange(min=150_000, currency="USD"),
|
|
126
|
+
location_types=["Remote"],
|
|
127
|
+
visa=True,
|
|
128
|
+
)
|
|
129
|
+
result = client.jobs.search(query)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Exporting jobs (async task flow)
|
|
133
|
+
|
|
134
|
+
Exports are processed server-side and returned as a downloadable file.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
query = {
|
|
138
|
+
"job_titles": ["Software Engineer", "Product Engineer", "Fullstack Engineer"],
|
|
139
|
+
"locations": [{"city": "San Francisco", "region": "California",
|
|
140
|
+
"country": "United States"}],
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# 1. Start the export -> returns a Task
|
|
144
|
+
task = client.jobs.export(query, format="json") # or format="csv"
|
|
145
|
+
|
|
146
|
+
# 2. Poll until it finishes -> (success, result)
|
|
147
|
+
success, result = client.tasks.poll(task)
|
|
148
|
+
if not success:
|
|
149
|
+
raise RuntimeError(f"Export failed: {result.error}")
|
|
150
|
+
|
|
151
|
+
# 3. Download the file (streamed to disk)
|
|
152
|
+
client.stream_file(result["download_url"], file_path="./jobs.json")
|
|
153
|
+
|
|
154
|
+
# 4. Stream jobs from the file (typed by default; uses constant memory)
|
|
155
|
+
for job in client.jobs.stream_file("./jobs.json"):
|
|
156
|
+
print(job.job_title)
|
|
157
|
+
|
|
158
|
+
# ...or get raw dicts
|
|
159
|
+
for row in client.jobs.stream_file("./jobs.json", return_type=dict):
|
|
160
|
+
...
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`poll()` accepts a `Task`, a task dict, or a task id, plus `interval`,
|
|
164
|
+
`timeout`, and an `on_progress` callback. The result dict contains
|
|
165
|
+
`download_url`, `file_size`, `record_count`, and `expiry_time`.
|
|
166
|
+
|
|
167
|
+
You can also stream **directly from the export URL** without saving to disk
|
|
168
|
+
(JSON Lines exports only):
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
for job in client.jobs.stream_url(result["download_url"]):
|
|
172
|
+
print(job.job_title)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Companies
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
# Search
|
|
179
|
+
companies = client.companies.search({"company_name": "Stripe"})
|
|
180
|
+
for company in companies:
|
|
181
|
+
print(company.company_name, company.company_slug)
|
|
182
|
+
|
|
183
|
+
# Get a company by slug — optionally with its jobs and live insights
|
|
184
|
+
company = client.companies.get("stripe", return_jobs=True, return_insights=True)
|
|
185
|
+
print(company.description_summary)
|
|
186
|
+
print(company.insights_data.headline.total_count)
|
|
187
|
+
|
|
188
|
+
# Bound helpers (the object remembers its client)
|
|
189
|
+
insights = company.insights()
|
|
190
|
+
jobs = company.get_jobs(limit=10)
|
|
191
|
+
|
|
192
|
+
# Company-scoped insights directly
|
|
193
|
+
insights = client.companies.insights("stripe", query={"days_ago": 30})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Typed vs. dict responses
|
|
197
|
+
|
|
198
|
+
Every method returns typed models by default. Pass `return_type=dict` to get
|
|
199
|
+
the raw API payload instead:
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
data = client.jobs.search(query, return_type=dict) # -> dict
|
|
203
|
+
job = client.jobs.get(job_id, return_type=dict) # -> dict
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Errors
|
|
207
|
+
|
|
208
|
+
All errors subclass `hirebase.HirebaseError`:
|
|
209
|
+
|
|
210
|
+
| Exception | Meaning |
|
|
211
|
+
|---|---|
|
|
212
|
+
| `ConfigurationError` | No API key / bad config |
|
|
213
|
+
| `AuthenticationError` | 401 — invalid API key |
|
|
214
|
+
| `PaymentRequiredError` | 402 — plan/credits required |
|
|
215
|
+
| `PermissionError_` | 403 — not allowed |
|
|
216
|
+
| `NotFoundError` | 404 |
|
|
217
|
+
| `RateLimitError` | 429 |
|
|
218
|
+
| `ServerError` | 5xx |
|
|
219
|
+
| `APIError` | any other non-2xx (`.status_code`, `.message`, `.body`) |
|
|
220
|
+
| `TaskFailed` / `TaskTimeout` | export task failed or timed out |
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
import hirebase
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
client.jobs.search(query)
|
|
227
|
+
except hirebase.RateLimitError:
|
|
228
|
+
...
|
|
229
|
+
except hirebase.APIError as e:
|
|
230
|
+
print(e.status_code, e.message)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Development
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
pip install -e ".[dev]"
|
|
237
|
+
|
|
238
|
+
# Offline unit tests (no network)
|
|
239
|
+
pytest
|
|
240
|
+
|
|
241
|
+
# Live integration tests against the real API
|
|
242
|
+
HIREBASE_API_KEY=sk_live_... pytest tests/test_integration.py -v
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
> If your environment preloads conflicting pytest plugins, run with
|
|
246
|
+
> `PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest`.
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hirebase"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Official Python SDK for the Hirebase API (jobs & company data)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Hirebase", email = "spencer@hirebase.org"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["hirebase", "jobs", "hiring", "api", "sdk", "company data"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
]
|
|
27
|
+
# Core runtime deps. requests powers the sync client, httpx the async client;
|
|
28
|
+
# both are widely installed and kept as hard deps so both clients work out of
|
|
29
|
+
# the box. pydantic provides the typed models.
|
|
30
|
+
dependencies = [
|
|
31
|
+
"requests>=2.28.0",
|
|
32
|
+
"httpx>=0.25.0",
|
|
33
|
+
"pydantic>=2.0.0",
|
|
34
|
+
"python-dotenv>=1.0.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
# Streaming very large JSON-array exports memory-efficiently.
|
|
39
|
+
streaming = [
|
|
40
|
+
"ijson>=3.2.0",
|
|
41
|
+
]
|
|
42
|
+
# The bundled command-line interface.
|
|
43
|
+
cli = [
|
|
44
|
+
"typer>=0.9.0",
|
|
45
|
+
"rich>=13.0.0",
|
|
46
|
+
]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest>=7.0.0",
|
|
49
|
+
"pytest-asyncio>=0.21.0",
|
|
50
|
+
"ijson>=3.2.0",
|
|
51
|
+
"typer>=0.9.0",
|
|
52
|
+
"rich>=13.0.0",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[project.scripts]
|
|
56
|
+
hirebase = "hirebase_cli.main:app"
|
|
57
|
+
|
|
58
|
+
[project.urls]
|
|
59
|
+
Homepage = "https://hirebase.org"
|
|
60
|
+
Documentation = "https://docs.hirebase.org"
|
|
61
|
+
Repository = "https://github.com/hirebase/hirebase-python-sdk"
|
|
62
|
+
|
|
63
|
+
[tool.pytest.ini_options]
|
|
64
|
+
testpaths = ["tests"]
|
|
65
|
+
|
|
66
|
+
[tool.setuptools.packages.find]
|
|
67
|
+
where = ["src"]
|
|
68
|
+
include = ["hirebase*", "hirebase_cli*"]
|
|
69
|
+
|
|
70
|
+
[tool.setuptools.package-dir]
|
|
71
|
+
"" = "src"
|
|
72
|
+
|
|
73
|
+
[tool.setuptools.package-data]
|
|
74
|
+
hirebase = ["py.typed"]
|
hirebase-0.1.1/setup.cfg
ADDED