Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
configured_endpoints: 10
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/tjc%2Fgrata-667059da0e38569628ffdc30fe45b81d2c0e9acdbdb7a40fd836576186f957bb.yml
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/tjc%2Fgrata-29fbf7a6e10684fb72680f05b0dd22e17f05b28be51d24451e2344905592a0c0.yml
43 changes: 20 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,38 @@ pip install grata
The full API of this library can be found in [api.md](api.md).

```python
import os
from grata import Grata

client = Grata()

company_detailed = client.enrich.create(
authorization="Token 840cda398b02093940807af4885853500c1cf5bb",
client = Grata(
token=os.environ.get("GRATA_API_KEY"), # This is the default and can be omitted
)

company_detailed = client.enrich.create()
print(company_detailed.count)
```

While you can provide a `token` keyword argument,
we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
to add `GRATA_API_KEY="GRATA_API_KEY"` to your `.env` file
so that your Token is not stored in source control.

## Async usage

Simply import `AsyncGrata` instead of `Grata` and use `await` with each API call:

```python
import os
import asyncio
from grata import AsyncGrata

client = AsyncGrata()
client = AsyncGrata(
token=os.environ.get("GRATA_API_KEY"), # This is the default and can be omitted
)


async def main() -> None:
company_detailed = await client.enrich.create(
authorization="Token 840cda398b02093940807af4885853500c1cf5bb",
)
company_detailed = await client.enrich.create()
print(company_detailed.count)


Expand Down Expand Up @@ -82,9 +89,7 @@ from grata import Grata
client = Grata()

try:
client.enrich.create(
authorization="Token 840cda398b02093940807af4885853500c1cf5bb",
)
client.enrich.create()
except grata.APIConnectionError as e:
print("The server could not be reached")
print(e.__cause__) # an underlying Exception, likely raised within httpx.
Expand Down Expand Up @@ -127,9 +132,7 @@ client = Grata(
)

# Or, configure per-request:
client.with_options(max_retries=5).enrich.create(
authorization="Token 840cda398b02093940807af4885853500c1cf5bb",
)
client.with_options(max_retries=5).enrich.create()
```

### Timeouts
Expand All @@ -152,9 +155,7 @@ client = Grata(
)

# Override per-request:
client.with_options(timeout=5.0).enrich.create(
authorization="Token 840cda398b02093940807af4885853500c1cf5bb",
)
client.with_options(timeout=5.0).enrich.create()
```

On timeout, an `APITimeoutError` is thrown.
Expand Down Expand Up @@ -195,9 +196,7 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
from grata import Grata

client = Grata()
response = client.enrich.with_raw_response.create(
authorization="Token 840cda398b02093940807af4885853500c1cf5bb",
)
response = client.enrich.with_raw_response.create()
print(response.headers.get('X-My-Header'))

enrich = response.parse() # get the object that `enrich.create()` would have returned
Expand All @@ -215,9 +214,7 @@ The above interface eagerly reads the full response body when you make the reque
To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.

```python
with client.enrich.with_streaming_response.create(
authorization="Token 840cda398b02093940807af4885853500c1cf5bb",
) as response:
with client.enrich.with_streaming_response.create() as response:
print(response.headers.get("X-My-Header"))

for line in response.iter_lines():
Expand Down
48 changes: 45 additions & 3 deletions src/grata/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
)
from ._version import __version__
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError
from ._exceptions import GrataError, APIStatusError
from ._base_client import (
DEFAULT_MAX_RETRIES,
SyncAPIClient,
Expand Down Expand Up @@ -54,10 +54,12 @@ class Grata(SyncAPIClient):
with_streaming_response: GrataWithStreamedResponse

# client options
token: str

def __init__(
self,
*,
token: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
Expand All @@ -77,7 +79,18 @@ def __init__(
# part of our public interface in the future.
_strict_response_validation: bool = False,
) -> None:
"""Construct a new synchronous grata client instance."""
"""Construct a new synchronous grata client instance.

This automatically infers the `token` argument from the `GRATA_API_KEY` environment variable if it is not provided.
"""
if token is None:
token = os.environ.get("GRATA_API_KEY")
if token is None:
raise GrataError(
"The token client option must be set either by passing token to the client or by setting the GRATA_API_KEY environment variable"
)
self.token = token

if base_url is None:
base_url = os.environ.get("GRATA_BASE_URL")
if base_url is None:
Expand Down Expand Up @@ -106,6 +119,12 @@ def __init__(
def qs(self) -> Querystring:
return Querystring(array_format="comma")

@property
@override
def auth_headers(self) -> dict[str, str]:
token = self.token
return {"Authorization": token}

@property
@override
def default_headers(self) -> dict[str, str | Omit]:
Expand All @@ -118,6 +137,7 @@ def default_headers(self) -> dict[str, str | Omit]:
def copy(
self,
*,
token: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
http_client: httpx.Client | None = None,
Expand Down Expand Up @@ -151,6 +171,7 @@ def copy(

http_client = http_client or self._client
return self.__class__(
token=token or self.token,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
Expand Down Expand Up @@ -207,10 +228,12 @@ class AsyncGrata(AsyncAPIClient):
with_streaming_response: AsyncGrataWithStreamedResponse

# client options
token: str

def __init__(
self,
*,
token: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
max_retries: int = DEFAULT_MAX_RETRIES,
Expand All @@ -230,7 +253,18 @@ def __init__(
# part of our public interface in the future.
_strict_response_validation: bool = False,
) -> None:
"""Construct a new async grata client instance."""
"""Construct a new async grata client instance.

This automatically infers the `token` argument from the `GRATA_API_KEY` environment variable if it is not provided.
"""
if token is None:
token = os.environ.get("GRATA_API_KEY")
if token is None:
raise GrataError(
"The token client option must be set either by passing token to the client or by setting the GRATA_API_KEY environment variable"
)
self.token = token

if base_url is None:
base_url = os.environ.get("GRATA_BASE_URL")
if base_url is None:
Expand Down Expand Up @@ -259,6 +293,12 @@ def __init__(
def qs(self) -> Querystring:
return Querystring(array_format="comma")

@property
@override
def auth_headers(self) -> dict[str, str]:
token = self.token
return {"Authorization": token}

@property
@override
def default_headers(self) -> dict[str, str | Omit]:
Expand All @@ -271,6 +311,7 @@ def default_headers(self) -> dict[str, str | Omit]:
def copy(
self,
*,
token: str | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
http_client: httpx.AsyncClient | None = None,
Expand Down Expand Up @@ -304,6 +345,7 @@ def copy(

http_client = http_client or self._client
return self.__class__(
token=token or self.token,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
Expand Down
4 changes: 0 additions & 4 deletions src/grata/resources/bulk.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ def with_streaming_response(self) -> BulkResourceWithStreamingResponse:
def enrich(
self,
*,
authorization: str,
company_uids: List[str] | NotGiven = NOT_GIVEN,
domains: List[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
Expand All @@ -76,7 +75,6 @@ def enrich(

timeout: Override the client-level default timeout for this request, in seconds
"""
extra_headers = {"Authorization": authorization, **(extra_headers or {})}
return self._post(
"/api/v1.4/bulk/enrich/",
body=maybe_transform(
Expand Down Expand Up @@ -116,7 +114,6 @@ def with_streaming_response(self) -> AsyncBulkResourceWithStreamingResponse:
async def enrich(
self,
*,
authorization: str,
company_uids: List[str] | NotGiven = NOT_GIVEN,
domains: List[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
Expand All @@ -143,7 +140,6 @@ async def enrich(

timeout: Override the client-level default timeout for this request, in seconds
"""
extra_headers = {"Authorization": authorization, **(extra_headers or {})}
return await self._post(
"/api/v1.4/bulk/enrich/",
body=await async_maybe_transform(
Expand Down
4 changes: 0 additions & 4 deletions src/grata/resources/enrich.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ def with_streaming_response(self) -> EnrichResourceWithStreamingResponse:
def create(
self,
*,
authorization: str,
company_uid: str | NotGiven = NOT_GIVEN,
domain: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
Expand Down Expand Up @@ -75,7 +74,6 @@ def create(

timeout: Override the client-level default timeout for this request, in seconds
"""
extra_headers = {"Authorization": authorization, **(extra_headers or {})}
return self._post(
"/api/v1.4/enrich/",
body=maybe_transform(
Expand Down Expand Up @@ -115,7 +113,6 @@ def with_streaming_response(self) -> AsyncEnrichResourceWithStreamingResponse:
async def create(
self,
*,
authorization: str,
company_uid: str | NotGiven = NOT_GIVEN,
domain: str | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
Expand Down Expand Up @@ -143,7 +140,6 @@ async def create(

timeout: Override the client-level default timeout for this request, in seconds
"""
extra_headers = {"Authorization": authorization, **(extra_headers or {})}
return await self._post(
"/api/v1.4/enrich/",
body=await async_maybe_transform(
Expand Down
Loading