luranta 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.
- luranta-0.1.0/LICENSE +21 -0
- luranta-0.1.0/PKG-INFO +75 -0
- luranta-0.1.0/README.md +51 -0
- luranta-0.1.0/pyproject.toml +37 -0
- luranta-0.1.0/src/luranta/__init__.py +66 -0
- luranta-0.1.0/src/luranta/_client.py +279 -0
- luranta-0.1.0/src/luranta/_errors.py +36 -0
- luranta-0.1.0/src/luranta/_transport.py +302 -0
- luranta-0.1.0/src/luranta/py.typed +1 -0
- luranta-0.1.0/src/luranta_generated/__init__.py +1 -0
- luranta-0.1.0/src/luranta_generated/models/company.py +152 -0
- luranta-0.1.0/src/luranta_generated/models/company_list.py +126 -0
- luranta-0.1.0/src/luranta_generated/models/company_list_data_inner.py +152 -0
- luranta-0.1.0/src/luranta_generated/models/job.py +323 -0
- luranta-0.1.0/src/luranta_generated/models/job_company.py +97 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation.py +136 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner.py +199 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_components_inner.py +163 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_components_inner_one_of.py +110 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_components_inner_one_of1.py +108 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_components_inner_one_of2.py +110 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_components_inner_one_of3.py +104 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_scope.py +191 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_scope_one_of.py +93 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_scope_one_of1.py +95 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_scope_one_of2.py +103 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_scope_one_of3.py +103 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_scope_one_of4.py +96 -0
- luranta-0.1.0/src/luranta_generated/models/job_compensation_packages_inner_scope_one_of5.py +93 -0
- luranta-0.1.0/src/luranta_generated/models/job_experience.py +101 -0
- luranta-0.1.0/src/luranta_generated/models/job_list.py +126 -0
- luranta-0.1.0/src/luranta_generated/models/job_list_data_inner.py +279 -0
- luranta-0.1.0/src/luranta_generated/models/job_location_disclosures_inner.py +105 -0
- luranta-0.1.0/src/luranta_generated/models/job_locations_inner.py +96 -0
- luranta-0.1.0/src/luranta_generated/models/job_primary_compensation_package.py +199 -0
- luranta-0.1.0/src/luranta_generated/models/location.py +109 -0
- luranta-0.1.0/src/luranta_generated/models/location_list.py +126 -0
- luranta-0.1.0/src/luranta_generated/models/location_list_data_inner.py +109 -0
- luranta-0.1.0/src/luranta_generated/models/problem_details.py +167 -0
- luranta-0.1.0/src/luranta_generated/models/problem_details_errors_inner.py +98 -0
- luranta-0.1.0/src/luranta_generated/models/taxonomy_snapshot.py +137 -0
- luranta-0.1.0/src/luranta_generated/models/taxonomy_snapshot_entries_inner.py +120 -0
- luranta-0.1.0/src/luranta_generated/models/tool.py +98 -0
- luranta-0.1.0/src/luranta_generated/models/tool_list.py +126 -0
- luranta-0.1.0/src/luranta_generated/models/tool_list_data_inner.py +98 -0
luranta-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Luranta
|
|
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.
|
luranta-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: luranta
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the Luranta API.
|
|
5
|
+
Project-URL: Documentation, https://docs.luranta.com
|
|
6
|
+
Project-URL: Source, https://github.com/luranta/sdk-python
|
|
7
|
+
Author-email: Luranta <support@luranta.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: <3.15,>=3.10
|
|
20
|
+
Requires-Dist: pydantic-core==2.46.4
|
|
21
|
+
Requires-Dist: pydantic==2.13.4
|
|
22
|
+
Requires-Dist: typing-extensions==4.16.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# `luranta`
|
|
26
|
+
|
|
27
|
+
Official Python SDK for Luranta's preview API, published as `luranta`.
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from luranta import Luranta
|
|
31
|
+
|
|
32
|
+
luranta = Luranta(api_key="lur_...")
|
|
33
|
+
|
|
34
|
+
for job in luranta.jobs.iterate({"roles": ["software-engineering"]}):
|
|
35
|
+
print(job.title)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`jobs`, `companies`, `tools`, and `locations` expose `list`, `retrieve` where
|
|
39
|
+
applicable, cursor iterators, and `with_raw_response` methods. Versioned role
|
|
40
|
+
and industry taxonomies are available through `luranta.taxonomies.roles` and
|
|
41
|
+
`luranta.taxonomies.industries`; use their `current()` and `get(version)`
|
|
42
|
+
methods. Raw responses include request IDs and Luranta billing headers.
|
|
43
|
+
|
|
44
|
+
Taxonomy values, tools, and locations are evolving resources. Languages are
|
|
45
|
+
accepted as canonical BCP 47 strings (for example `en-GB` or `zh-Hans`) rather
|
|
46
|
+
than a generated enum.
|
|
47
|
+
|
|
48
|
+
Only HTTP `408`, `429`, `500`, `502`, `503`, and `504` responses carrying
|
|
49
|
+
valid RFC 9457 Problem Details with `retryable: true` and no billing evidence
|
|
50
|
+
are retried. `Retry-After` is honored. Network failures are ambiguous and
|
|
51
|
+
immediately raise `TransportError`. Cursor iterators stop on malformed or
|
|
52
|
+
repeated cursors rather than risk duplicate billable reads.
|
|
53
|
+
|
|
54
|
+
## Generation
|
|
55
|
+
|
|
56
|
+
`src/luranta_generated` contains disposable models generated from the canonical
|
|
57
|
+
`../../apps/api/openapi/openapi.json` using OpenAPI Generator engine 7.24.0
|
|
58
|
+
through the exact 2.40.1 CLI wrapper. Generated HTTP code is intentionally
|
|
59
|
+
excluded so the safe runtime above is the only transport. A deterministic
|
|
60
|
+
response-only transform widens schema enums to strings while retaining their
|
|
61
|
+
known values as metadata, so a new server enum does not break an older SDK.
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
bun run generate
|
|
65
|
+
bun run generate:check
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Luranta API keys belong only in trusted server-side environments. Never expose
|
|
69
|
+
one in browser or mobile application code.
|
|
70
|
+
|
|
71
|
+
The preview package supports the exact tested Python 3.10 through 3.14
|
|
72
|
+
maintenance lines.
|
|
73
|
+
|
|
74
|
+
The public source repository is [luranta/sdk-python](https://github.com/luranta/sdk-python).
|
|
75
|
+
Releases use PyPI Trusted Publishing with attestations.
|
luranta-0.1.0/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# `luranta`
|
|
2
|
+
|
|
3
|
+
Official Python SDK for Luranta's preview API, published as `luranta`.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from luranta import Luranta
|
|
7
|
+
|
|
8
|
+
luranta = Luranta(api_key="lur_...")
|
|
9
|
+
|
|
10
|
+
for job in luranta.jobs.iterate({"roles": ["software-engineering"]}):
|
|
11
|
+
print(job.title)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`jobs`, `companies`, `tools`, and `locations` expose `list`, `retrieve` where
|
|
15
|
+
applicable, cursor iterators, and `with_raw_response` methods. Versioned role
|
|
16
|
+
and industry taxonomies are available through `luranta.taxonomies.roles` and
|
|
17
|
+
`luranta.taxonomies.industries`; use their `current()` and `get(version)`
|
|
18
|
+
methods. Raw responses include request IDs and Luranta billing headers.
|
|
19
|
+
|
|
20
|
+
Taxonomy values, tools, and locations are evolving resources. Languages are
|
|
21
|
+
accepted as canonical BCP 47 strings (for example `en-GB` or `zh-Hans`) rather
|
|
22
|
+
than a generated enum.
|
|
23
|
+
|
|
24
|
+
Only HTTP `408`, `429`, `500`, `502`, `503`, and `504` responses carrying
|
|
25
|
+
valid RFC 9457 Problem Details with `retryable: true` and no billing evidence
|
|
26
|
+
are retried. `Retry-After` is honored. Network failures are ambiguous and
|
|
27
|
+
immediately raise `TransportError`. Cursor iterators stop on malformed or
|
|
28
|
+
repeated cursors rather than risk duplicate billable reads.
|
|
29
|
+
|
|
30
|
+
## Generation
|
|
31
|
+
|
|
32
|
+
`src/luranta_generated` contains disposable models generated from the canonical
|
|
33
|
+
`../../apps/api/openapi/openapi.json` using OpenAPI Generator engine 7.24.0
|
|
34
|
+
through the exact 2.40.1 CLI wrapper. Generated HTTP code is intentionally
|
|
35
|
+
excluded so the safe runtime above is the only transport. A deterministic
|
|
36
|
+
response-only transform widens schema enums to strings while retaining their
|
|
37
|
+
known values as metadata, so a new server enum does not break an older SDK.
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
bun run generate
|
|
41
|
+
bun run generate:check
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Luranta API keys belong only in trusted server-side environments. Never expose
|
|
45
|
+
one in browser or mobile application code.
|
|
46
|
+
|
|
47
|
+
The preview package supports the exact tested Python 3.10 through 3.14
|
|
48
|
+
maintenance lines.
|
|
49
|
+
|
|
50
|
+
The public source repository is [luranta/sdk-python](https://github.com/luranta/sdk-python).
|
|
51
|
+
Releases use PyPI Trusted Publishing with attestations.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling==1.31.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "luranta"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Official Python SDK for the Luranta API."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10,<3.15"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "Luranta", email = "support@luranta.com" }]
|
|
13
|
+
dependencies = ["pydantic==2.13.4", "pydantic-core==2.46.4", "typing-extensions==4.16.0"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Documentation = "https://docs.luranta.com"
|
|
28
|
+
Source = "https://github.com/luranta/sdk-python"
|
|
29
|
+
|
|
30
|
+
[tool.luranta]
|
|
31
|
+
release-enabled = true
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.sdist]
|
|
34
|
+
include = ["/src", "/LICENSE", "/README.md"]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.wheel]
|
|
37
|
+
packages = ["src/luranta", "src/luranta_generated"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from luranta_generated.models.company import Company
|
|
2
|
+
from luranta_generated.models.company_list import CompanyList
|
|
3
|
+
from luranta_generated.models.company_list_data_inner import (
|
|
4
|
+
CompanyListDataInner as CompanySummary,
|
|
5
|
+
)
|
|
6
|
+
from luranta_generated.models.job import Job
|
|
7
|
+
from luranta_generated.models.job_list import JobList
|
|
8
|
+
from luranta_generated.models.job_list_data_inner import JobListDataInner as JobSummary
|
|
9
|
+
from luranta_generated.models.location import Location
|
|
10
|
+
from luranta_generated.models.location_list import LocationList
|
|
11
|
+
from luranta_generated.models.location_list_data_inner import (
|
|
12
|
+
LocationListDataInner as LocationSummary,
|
|
13
|
+
)
|
|
14
|
+
from luranta_generated.models.problem_details import ProblemDetails
|
|
15
|
+
from luranta_generated.models.taxonomy_snapshot import TaxonomySnapshot
|
|
16
|
+
from luranta_generated.models.taxonomy_snapshot_entries_inner import (
|
|
17
|
+
TaxonomySnapshotEntriesInner as TaxonomyEntry,
|
|
18
|
+
)
|
|
19
|
+
from luranta_generated.models.tool import Tool
|
|
20
|
+
from luranta_generated.models.tool_list import ToolList
|
|
21
|
+
from luranta_generated.models.tool_list_data_inner import ToolListDataInner as ToolSummary
|
|
22
|
+
|
|
23
|
+
from ._client import (
|
|
24
|
+
CatalogueListParams,
|
|
25
|
+
LocationsRawResource,
|
|
26
|
+
LocationsResource,
|
|
27
|
+
Luranta,
|
|
28
|
+
TaxonomiesResource,
|
|
29
|
+
TaxonomyResource,
|
|
30
|
+
ToolsRawResource,
|
|
31
|
+
ToolsResource,
|
|
32
|
+
)
|
|
33
|
+
from ._errors import LurantaProblemError, TransportError
|
|
34
|
+
from ._transport import HttpResponse, QueryParams, QueryValue, RawResponse
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"Company",
|
|
38
|
+
"CompanyList",
|
|
39
|
+
"CompanySummary",
|
|
40
|
+
"CatalogueListParams",
|
|
41
|
+
"HttpResponse",
|
|
42
|
+
"Job",
|
|
43
|
+
"JobList",
|
|
44
|
+
"JobSummary",
|
|
45
|
+
"Location",
|
|
46
|
+
"LocationList",
|
|
47
|
+
"LocationSummary",
|
|
48
|
+
"LocationsRawResource",
|
|
49
|
+
"LocationsResource",
|
|
50
|
+
"Luranta",
|
|
51
|
+
"LurantaProblemError",
|
|
52
|
+
"ProblemDetails",
|
|
53
|
+
"QueryParams",
|
|
54
|
+
"QueryValue",
|
|
55
|
+
"RawResponse",
|
|
56
|
+
"TaxonomiesResource",
|
|
57
|
+
"TaxonomyEntry",
|
|
58
|
+
"TaxonomyResource",
|
|
59
|
+
"TaxonomySnapshot",
|
|
60
|
+
"Tool",
|
|
61
|
+
"ToolList",
|
|
62
|
+
"ToolSummary",
|
|
63
|
+
"ToolsRawResource",
|
|
64
|
+
"ToolsResource",
|
|
65
|
+
"TransportError",
|
|
66
|
+
]
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterator
|
|
4
|
+
from typing import Final
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
from typing_extensions import NotRequired, Required, TypedDict
|
|
7
|
+
|
|
8
|
+
from luranta_generated.models.company import Company
|
|
9
|
+
from luranta_generated.models.company_list import CompanyList
|
|
10
|
+
from luranta_generated.models.company_list_data_inner import CompanyListDataInner
|
|
11
|
+
from luranta_generated.models.job import Job
|
|
12
|
+
from luranta_generated.models.job_list import JobList
|
|
13
|
+
from luranta_generated.models.job_list_data_inner import JobListDataInner
|
|
14
|
+
from luranta_generated.models.location import Location
|
|
15
|
+
from luranta_generated.models.location_list import LocationList
|
|
16
|
+
from luranta_generated.models.location_list_data_inner import LocationListDataInner
|
|
17
|
+
from luranta_generated.models.taxonomy_snapshot import TaxonomySnapshot
|
|
18
|
+
from luranta_generated.models.tool import Tool
|
|
19
|
+
from luranta_generated.models.tool_list import ToolList
|
|
20
|
+
from luranta_generated.models.tool_list_data_inner import ToolListDataInner
|
|
21
|
+
|
|
22
|
+
from ._transport import (
|
|
23
|
+
ClientTransport,
|
|
24
|
+
QueryParams,
|
|
25
|
+
RawResponse,
|
|
26
|
+
Transport,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
DEFAULT_BASE_URL: Final = "https://api.luranta.com"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CatalogueListParams(TypedDict):
|
|
33
|
+
query: Required[str]
|
|
34
|
+
cursor: NotRequired[str]
|
|
35
|
+
limit: NotRequired[int]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Luranta:
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
*,
|
|
42
|
+
api_key: str,
|
|
43
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
44
|
+
max_retries: int = 2,
|
|
45
|
+
timeout: float = 30.0,
|
|
46
|
+
_transport: Transport | None = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
transport = ClientTransport(
|
|
49
|
+
api_key=api_key,
|
|
50
|
+
base_url=base_url,
|
|
51
|
+
max_retries=max_retries,
|
|
52
|
+
timeout=timeout,
|
|
53
|
+
transport=_transport,
|
|
54
|
+
)
|
|
55
|
+
self.jobs = JobsResource(transport)
|
|
56
|
+
self.companies = CompaniesResource(transport)
|
|
57
|
+
self.taxonomies = TaxonomiesResource(transport)
|
|
58
|
+
self.tools = ToolsResource(transport)
|
|
59
|
+
self.locations = LocationsResource(transport)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class JobsResource:
|
|
63
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
64
|
+
self._transport = transport
|
|
65
|
+
self.with_raw_response = JobsRawResource(transport)
|
|
66
|
+
|
|
67
|
+
def list(self, params: QueryParams | None = None) -> JobList:
|
|
68
|
+
return self._transport.request("/v0/jobs", JobList, params)
|
|
69
|
+
|
|
70
|
+
def retrieve(self, job_id: str) -> Job:
|
|
71
|
+
return self._transport.request(
|
|
72
|
+
f"/v0/jobs/{quote(job_id, safe='')}",
|
|
73
|
+
Job,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def iterate(self, params: QueryParams | None = None) -> Iterator[JobListDataInner]:
|
|
77
|
+
original = dict(params or {})
|
|
78
|
+
current = dict(original)
|
|
79
|
+
seen_cursors = _initial_cursors(original)
|
|
80
|
+
while True:
|
|
81
|
+
page = self.list(current)
|
|
82
|
+
yield from page.data
|
|
83
|
+
cursor = _advance_cursor(page.has_more, page.next_cursor, seen_cursors)
|
|
84
|
+
if cursor is None:
|
|
85
|
+
return
|
|
86
|
+
current = {**original, "cursor": cursor}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class JobsRawResource:
|
|
90
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
91
|
+
self._transport = transport
|
|
92
|
+
|
|
93
|
+
def list(self, params: QueryParams | None = None) -> RawResponse[JobList]:
|
|
94
|
+
return self._transport.request_raw("/v0/jobs", JobList, params)
|
|
95
|
+
|
|
96
|
+
def retrieve(self, job_id: str) -> RawResponse[Job]:
|
|
97
|
+
return self._transport.request_raw(
|
|
98
|
+
f"/v0/jobs/{quote(job_id, safe='')}",
|
|
99
|
+
Job,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class CompaniesResource:
|
|
104
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
105
|
+
self._transport = transport
|
|
106
|
+
self.with_raw_response = CompaniesRawResource(transport)
|
|
107
|
+
|
|
108
|
+
def list(self, params: QueryParams | None = None) -> CompanyList:
|
|
109
|
+
return self._transport.request("/v0/companies", CompanyList, params)
|
|
110
|
+
|
|
111
|
+
def retrieve(self, company_id: str) -> Company:
|
|
112
|
+
return self._transport.request(
|
|
113
|
+
f"/v0/companies/{quote(company_id, safe='')}",
|
|
114
|
+
Company,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def iterate(
|
|
118
|
+
self,
|
|
119
|
+
params: QueryParams | None = None,
|
|
120
|
+
) -> Iterator[CompanyListDataInner]:
|
|
121
|
+
original = dict(params or {})
|
|
122
|
+
current = dict(original)
|
|
123
|
+
seen_cursors = _initial_cursors(original)
|
|
124
|
+
while True:
|
|
125
|
+
page = self.list(current)
|
|
126
|
+
yield from page.data
|
|
127
|
+
cursor = _advance_cursor(page.has_more, page.next_cursor, seen_cursors)
|
|
128
|
+
if cursor is None:
|
|
129
|
+
return
|
|
130
|
+
current = {**original, "cursor": cursor}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class CompaniesRawResource:
|
|
134
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
135
|
+
self._transport = transport
|
|
136
|
+
|
|
137
|
+
def list(self, params: QueryParams | None = None) -> RawResponse[CompanyList]:
|
|
138
|
+
return self._transport.request_raw("/v0/companies", CompanyList, params)
|
|
139
|
+
|
|
140
|
+
def retrieve(self, company_id: str) -> RawResponse[Company]:
|
|
141
|
+
return self._transport.request_raw(
|
|
142
|
+
f"/v0/companies/{quote(company_id, safe='')}",
|
|
143
|
+
Company,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class TaxonomyResource:
|
|
148
|
+
def __init__(self, transport: ClientTransport, name: str) -> None:
|
|
149
|
+
self._transport = transport
|
|
150
|
+
self._path = f"/v0/taxonomies/{name}"
|
|
151
|
+
|
|
152
|
+
def current(self) -> TaxonomySnapshot:
|
|
153
|
+
return self._transport.request(self._path, TaxonomySnapshot)
|
|
154
|
+
|
|
155
|
+
def get(self, version: int | str) -> TaxonomySnapshot:
|
|
156
|
+
return self._transport.request(
|
|
157
|
+
f"{self._path}/{quote(str(version), safe='')}",
|
|
158
|
+
TaxonomySnapshot,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class TaxonomiesResource:
|
|
163
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
164
|
+
self.roles = TaxonomyResource(transport, "roles")
|
|
165
|
+
self.industries = TaxonomyResource(transport, "industries")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class ToolsResource:
|
|
169
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
170
|
+
self._transport = transport
|
|
171
|
+
self.with_raw_response = ToolsRawResource(transport)
|
|
172
|
+
|
|
173
|
+
def list(self, params: CatalogueListParams) -> ToolList:
|
|
174
|
+
return self._transport.request("/v0/tools", ToolList, params)
|
|
175
|
+
|
|
176
|
+
def retrieve(self, code: str) -> Tool:
|
|
177
|
+
return self._transport.request(
|
|
178
|
+
f"/v0/tools/{quote(code, safe='')}",
|
|
179
|
+
Tool,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def iterate(self, params: CatalogueListParams) -> Iterator[ToolListDataInner]:
|
|
183
|
+
original = dict(params)
|
|
184
|
+
current = dict(original)
|
|
185
|
+
seen_cursors = _initial_cursors(original)
|
|
186
|
+
while True:
|
|
187
|
+
page = self.list(current)
|
|
188
|
+
yield from page.data
|
|
189
|
+
cursor = _advance_cursor(page.has_more, page.next_cursor, seen_cursors)
|
|
190
|
+
if cursor is None:
|
|
191
|
+
return
|
|
192
|
+
current = {**original, "cursor": cursor}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ToolsRawResource:
|
|
196
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
197
|
+
self._transport = transport
|
|
198
|
+
|
|
199
|
+
def list(self, params: CatalogueListParams) -> RawResponse[ToolList]:
|
|
200
|
+
return self._transport.request_raw("/v0/tools", ToolList, params)
|
|
201
|
+
|
|
202
|
+
def retrieve(self, code: str) -> RawResponse[Tool]:
|
|
203
|
+
return self._transport.request_raw(
|
|
204
|
+
f"/v0/tools/{quote(code, safe='')}",
|
|
205
|
+
Tool,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class LocationsResource:
|
|
210
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
211
|
+
self._transport = transport
|
|
212
|
+
self.with_raw_response = LocationsRawResource(transport)
|
|
213
|
+
|
|
214
|
+
def list(self, params: CatalogueListParams) -> LocationList:
|
|
215
|
+
return self._transport.request("/v0/locations", LocationList, params)
|
|
216
|
+
|
|
217
|
+
def retrieve(self, location_id: str) -> Location:
|
|
218
|
+
return self._transport.request(
|
|
219
|
+
f"/v0/locations/{quote(location_id, safe='')}",
|
|
220
|
+
Location,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
def iterate(
|
|
224
|
+
self,
|
|
225
|
+
params: CatalogueListParams,
|
|
226
|
+
) -> Iterator[LocationListDataInner]:
|
|
227
|
+
original = dict(params or {})
|
|
228
|
+
current = dict(original)
|
|
229
|
+
seen_cursors = _initial_cursors(original)
|
|
230
|
+
while True:
|
|
231
|
+
page = self.list(current)
|
|
232
|
+
yield from page.data
|
|
233
|
+
cursor = _advance_cursor(page.has_more, page.next_cursor, seen_cursors)
|
|
234
|
+
if cursor is None:
|
|
235
|
+
return
|
|
236
|
+
current = {**original, "cursor": cursor}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class LocationsRawResource:
|
|
240
|
+
def __init__(self, transport: ClientTransport) -> None:
|
|
241
|
+
self._transport = transport
|
|
242
|
+
|
|
243
|
+
def list(self, params: CatalogueListParams) -> RawResponse[LocationList]:
|
|
244
|
+
return self._transport.request_raw("/v0/locations", LocationList, params)
|
|
245
|
+
|
|
246
|
+
def retrieve(self, location_id: str) -> RawResponse[Location]:
|
|
247
|
+
return self._transport.request_raw(
|
|
248
|
+
f"/v0/locations/{quote(location_id, safe='')}",
|
|
249
|
+
Location,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _initial_cursors(params: QueryParams) -> set[str]:
|
|
254
|
+
cursor = params.get("cursor")
|
|
255
|
+
return {cursor} if isinstance(cursor, str) else set()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _advance_cursor(
|
|
259
|
+
has_more: bool,
|
|
260
|
+
next_cursor: str | None,
|
|
261
|
+
seen_cursors: set[str],
|
|
262
|
+
) -> str | None:
|
|
263
|
+
if not has_more:
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
from ._errors import TransportError
|
|
267
|
+
|
|
268
|
+
if next_cursor is None:
|
|
269
|
+
raise TransportError(
|
|
270
|
+
"Luranta returned has_more without the next cursor required to "
|
|
271
|
+
"continue pagination."
|
|
272
|
+
)
|
|
273
|
+
if next_cursor in seen_cursors:
|
|
274
|
+
raise TransportError(
|
|
275
|
+
"Luranta returned a repeated cursor; pagination stopped to prevent "
|
|
276
|
+
"duplicate billable reads."
|
|
277
|
+
)
|
|
278
|
+
seen_cursors.add(next_cursor)
|
|
279
|
+
return next_cursor
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from luranta_generated.models.problem_details import ProblemDetails
|
|
4
|
+
|
|
5
|
+
from ._transport import HttpResponse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LurantaProblemError(Exception):
|
|
9
|
+
"""An HTTP error represented by Luranta RFC 9457 Problem Details."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
problem: ProblemDetails | None,
|
|
14
|
+
response: HttpResponse,
|
|
15
|
+
) -> None:
|
|
16
|
+
self.problem = problem
|
|
17
|
+
self.response = response
|
|
18
|
+
self.status = response.status_code
|
|
19
|
+
self.code = problem.code if problem is not None else "unexpected_error_response"
|
|
20
|
+
self.request_id = (
|
|
21
|
+
str(problem.request_id)
|
|
22
|
+
if problem is not None
|
|
23
|
+
else response.header("X-Request-Id")
|
|
24
|
+
)
|
|
25
|
+
self.retryable = problem.retryable if problem is not None else False
|
|
26
|
+
detail = (
|
|
27
|
+
problem.detail
|
|
28
|
+
if problem is not None
|
|
29
|
+
else f"Luranta returned HTTP {response.status_code} without valid Problem Details."
|
|
30
|
+
)
|
|
31
|
+
super().__init__(detail)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TransportError(Exception):
|
|
35
|
+
"""A request failure without a trustworthy, parseable HTTP response."""
|
|
36
|
+
|