Skip to content

Commit 1c1c3ad

Browse files
Update to use configclass
1 parent 497ea99 commit 1c1c3ad

File tree

5 files changed

+219
-105
lines changed

5 files changed

+219
-105
lines changed

README.md

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -41,47 +41,50 @@ Check the [Python Connect SDK Example](example/README.md) to see an example of i
4141

4242
3. Use the SDK:
4343

44-
- Read a secret:
45-
46-
```python
47-
from onepasswordconnectsdk.client import (
48-
Client,
49-
new_client_from_environment,
50-
)
51-
52-
connect_client: Client = new_client_from_environment()
53-
54-
client.get_item("{item_id}", "{vault_id}")
55-
```
56-
57-
- Write a secret:
58-
59-
```python
60-
from onepasswordconnectsdk.client import (
61-
Client,
62-
new_client_from_environment,
63-
}
64-
65-
from onepasswordconnectsdk.models import (
66-
Item,
67-
ItemVault,
68-
Field
69-
)
70-
71-
connect_client: Client = new_client_from_environment()
72-
73-
# Example item creation. Create an item with your desired arguments.
74-
item = Item(
75-
vault=ItemVault(id=op_vault),
76-
id="custom_id",
77-
title="newtitle",
78-
category="LOGIN",
79-
tags=["1password-connect"],
80-
fields=[Field(value="new_user", purpose="USERNAME")],
81-
)
82-
83-
new_item = connect_client.create_item(op_vault, item)
84-
```
44+
Choose between synchronous or asynchronous clients:
45+
46+
```python
47+
# Synchronous client
48+
from onepasswordconnectsdk.client import Client, new_client_from_environment
49+
50+
# Create client using environment variables
51+
client: Client = new_client_from_environment()
52+
53+
# Read a secret
54+
item = client.get_item("{item_id}", "{vault_id}")
55+
56+
# Write a secret
57+
from onepasswordconnectsdk.models import Item, ItemVault, Field
58+
59+
new_item = Item(
60+
vault=ItemVault(id=vault_id),
61+
title="Example Login",
62+
category="LOGIN",
63+
fields=[Field(value="username123", purpose="USERNAME")]
64+
)
65+
created_item = client.create_item(vault_id, new_item)
66+
```
67+
68+
```python
69+
# Asynchronous client
70+
import asyncio
71+
from onepasswordconnectsdk.async_client import AsyncClient, new_async_client_from_environment
72+
73+
async def main():
74+
# Create client using environment variables
75+
client: AsyncClient = new_async_client_from_environment()
76+
77+
try:
78+
# Read and write secrets asynchronously
79+
item = await client.get_item("{item_id}", "{vault_id}")
80+
created_item = await client.create_item(vault_id, new_item)
81+
finally:
82+
await client.session.aclose()
83+
84+
asyncio.run(main())
85+
```
86+
87+
Both client types support additional configuration through [httpx client options](https://www.python-httpx.org/api/#client).
8588

8689
For more examples of how to use the SDK, check out [USAGE.md](USAGE.md).
8790

USAGE.md

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
## Creating a Connect API Client
44

5-
There are two methods available for creating a client:
5+
The SDK provides both synchronous and asynchronous clients. Each type has two creation methods:
66

7-
- `new_client_from_environment`: Builds a new client for interacting with 1Password Connect using the `OP_CONNECT_TOKEN` and `OP_CONNECT_HOST` environment variables.
8-
- `new_client`: Builds a new client for interacting with 1Password Connect. Accepts the hostname of 1Password Connect and the API token generated for the application.
7+
### Synchronous Client
98

109
```python
1110
from onepasswordconnectsdk.client import (
@@ -14,21 +13,51 @@ from onepasswordconnectsdk.client import (
1413
new_client
1514
)
1615

17-
# creating client using OP_CONNECT_TOKEN and OP_CONNECT_HOST environment variables
18-
connect_client_from_env: Client = new_client_from_environment()
16+
# Create client using environment variables
17+
connect_client: Client = new_client_from_environment()
1918

20-
# creates a client by supplying hostname and 1Password Connect API token
21-
connect_client_from_token: Client = new_client(
19+
# Create client with explicit configuration
20+
connect_client: Client = new_client(
2221
"{1Password_Connect_Host}",
2322
"{1Password_Connect_API_Token}")
2423

25-
# creates async client
26-
connect_async_client: Client = new_client(
24+
# Create client with additional httpx options
25+
connect_client: Client = new_client(
2726
"{1Password_Connect_Host}",
2827
"{1Password_Connect_API_Token}",
29-
True)
28+
verify="path/to/certificate.pem", # SSL certificate
29+
timeout=30.0, # Custom timeout
30+
proxies={"http://": "http://proxy.example.com"}) # Proxy configuration
3031
```
3132

33+
### Asynchronous Client
34+
35+
```python
36+
from onepasswordconnectsdk.async_client import (
37+
AsyncClient,
38+
new_async_client_from_environment,
39+
new_async_client
40+
)
41+
42+
# Create async client using environment variables
43+
async_client: AsyncClient = new_async_client_from_environment()
44+
45+
# Create async client with explicit configuration
46+
async_client: AsyncClient = new_async_client(
47+
"{1Password_Connect_Host}",
48+
"{1Password_Connect_API_Token}")
49+
50+
# Create async client with additional httpx options
51+
async_client: AsyncClient = new_async_client(
52+
"{1Password_Connect_Host}",
53+
"{1Password_Connect_API_Token}",
54+
verify="path/to/certificate.pem", # SSL certificate
55+
timeout=30.0, # Custom timeout
56+
proxies={"http://": "http://proxy.example.com"}) # Proxy configuration
57+
```
58+
59+
Both client types support all [httpx client options](https://www.python-httpx.org/api/#client) through their respective configuration classes.
60+
3261
## Environment Variables
3362

3463
- **OP_CONNECT_TOKEN** – The token to be used to authenticate with the 1Password Connect API.
@@ -38,9 +67,6 @@ connect_async_client: Client = new_client(
3867
- `http://localhost:8080` if the Connect server is running in Docker on the same host.
3968
- `http(s)://<ip>:8080` or `http(s)://<hostname>:8080` if the Connect server is running on another host.
4069
- **OP_VAULT** - The default vault to fetch items from if not specified.
41-
- **OP_CONNECT_CLIENT_ASYNC** - Whether to use async client or not. Possible values are:
42-
- True - to use async client
43-
- False - to use synchronous client (this is used by default)
4470

4571

4672
## Working with Vaults
@@ -147,23 +173,32 @@ CONFIG = Config()
147173
values_object = onepasswordconnectsdk.load(connect_client, CONFIG)
148174
```
149175

150-
## Async client
176+
## Using the Async Client
177+
178+
The async client provides the same functionality as the sync client but with async/await syntax:
151179

152-
All the examples above can work using an async client.
153180
```python
154181
import asyncio
155-
156-
# initialize async client by passing `is_async = True`
157-
async_client: Client = new_client(
158-
"{1Password_Connect_Host}",
159-
"{1Password_Connect_API_Token}",
160-
True)
182+
from onepasswordconnectsdk.async_client import AsyncClient, new_async_client
161183

162184
async def main():
163-
vaults = await async_client.get_vaults()
164-
item = await async_client.get_item("{item_id}", "{vault_id}")
165-
# do something with vaults and item
166-
await async_client.session.aclose() # close the client gracefully when you are done
185+
# Create async client with optional httpx configuration
186+
async_client: AsyncClient = new_async_client(
187+
"{1Password_Connect_Host}",
188+
"{1Password_Connect_API_Token}",
189+
timeout=30.0 # Optional httpx configuration
190+
)
191+
192+
try:
193+
# Use the client
194+
vaults = await async_client.get_vaults()
195+
item = await async_client.get_item("{item_id}", "{vault_id}")
196+
# Do something with vaults and item
197+
finally:
198+
# Always close the client when done
199+
await async_client.session.aclose()
167200

168201
asyncio.run(main())
169-
```
202+
```
203+
204+
All the examples shown above for the sync client work the same way with the async client, just with async/await syntax.

src/onepasswordconnectsdk/async_client.py

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,24 @@
2121
class AsyncClient:
2222
"""Python Async Client Class"""
2323

24-
def __init__(self, url: str, token: str) -> None:
25-
"""Initialize async client"""
26-
self.url = url
27-
self.token = token
28-
self.session = self.create_session(url, token)
24+
def __init__(self, config: 'AsyncClientConfig') -> None:
25+
"""Initialize async client
26+
27+
Args:
28+
config: AsyncClientConfig instance containing all client configuration
29+
"""
30+
self.url = config.url
31+
self.token = config.token
32+
self.session = self.create_session(config)
2933
self.serializer = Serializer()
3034

31-
def create_session(self, url: str, token: str) -> httpx.AsyncClient:
32-
return httpx.AsyncClient(base_url=url, headers=self.build_headers(token), timeout=get_timeout())
35+
def create_session(self, config: 'AsyncClientConfig') -> httpx.AsyncClient:
36+
"""Create an HTTP session using the provided configuration"""
37+
# Update headers in the existing config
38+
headers = config.headers or {}
39+
headers.update(self.build_headers(config.token))
40+
config.headers = headers
41+
return config
3342

3443
def build_headers(self, token: str) -> Dict[str, str]:
3544
return build_headers(token)
@@ -378,27 +387,32 @@ def sanitize_for_serialization(self, obj):
378387
return self.serializer.sanitize_for_serialization(obj)
379388

380389

381-
def new_async_client(url: str, token: str) -> AsyncClient:
390+
def new_async_client(url: str, token: str, **kwargs) -> AsyncClient:
382391
"""Builds a new client for interacting with 1Password Connect
383-
Parameters:
384-
url: The url of the 1Password Connect API
385-
token: The 1Password Service Account token
392+
393+
Args:
394+
url: The url of the 1Password Connect API
395+
token: The 1Password Service Account token
396+
**kwargs: Additional httpx.AsyncClient configuration options
386397
387398
Returns:
388-
AsyncClient: The 1Password Connect client
399+
AsyncClient: The 1Password Connect client
389400
"""
390-
return AsyncClient(url, token)
401+
from onepasswordconnectsdk.config import AsyncClientConfig
402+
config = AsyncClientConfig(url=url, token=token, **kwargs)
403+
return AsyncClient(config)
391404

392405

393-
def new_async_client_from_environment(url: str = None) -> AsyncClient:
406+
def new_async_client_from_environment(url: str = None, **kwargs) -> AsyncClient:
394407
"""Builds a new client for interacting with 1Password Connect
395408
using the OP_CONNECT_TOKEN environment variable
396409
397-
Parameters:
398-
url: The url of the 1Password Connect API
410+
Args:
411+
url: The url of the 1Password Connect API
412+
**kwargs: Additional httpx.AsyncClient configuration options
399413
400414
Returns:
401-
AsyncClient: The 1Password Connect client
415+
AsyncClient: The 1Password Connect client
402416
"""
403417
token = os.environ.get(ENV_SERVICE_ACCOUNT_JWT_VARIABLE)
404418

@@ -415,4 +429,4 @@ def new_async_client_from_environment(url: str = None) -> AsyncClient:
415429
f"{ENV_SERVICE_ACCOUNT_JWT_VARIABLE} variable"
416430
)
417431

418-
return new_async_client(url, token)
432+
return new_async_client(url, token, certificate, **kwargs)

src/onepasswordconnectsdk/client.py

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,24 @@
2222
class Client:
2323
"""Python Client Class"""
2424

25-
def __init__(self, url: str, token: str) -> None:
26-
"""Initialize client"""
27-
self.url = url
28-
self.token = token
29-
self.session = self.create_session(url, token)
25+
def __init__(self, config: 'ClientConfig') -> None:
26+
"""Initialize client
27+
28+
Args:
29+
config: ClientConfig instance containing all client configuration
30+
"""
31+
self.url = config.url
32+
self.token = config.token
33+
self.session = self.create_session(config)
3034
self.serializer = Serializer()
3135

32-
def create_session(self, url: str, token: str) -> httpx.Client:
33-
return httpx.Client(base_url=url, headers=self.build_headers(token), timeout=get_timeout())
36+
def create_session(self, config: 'ClientConfig') -> httpx.Client:
37+
"""Create an HTTP session using the provided configuration"""
38+
# Update headers in the existing config
39+
headers = config.headers or {}
40+
headers.update(self.build_headers(config.token))
41+
config.headers = headers
42+
return config
3443

3544
def build_headers(self, token: str) -> Dict[str, str]:
3645
return build_headers(token)
@@ -379,27 +388,32 @@ def sanitize_for_serialization(self, obj):
379388
return self.serializer.sanitize_for_serialization(obj)
380389

381390

382-
def new_client(url: str, token: str) -> Client:
391+
def new_client(url: str, token: str, **kwargs) -> Client:
383392
"""Builds a new client for interacting with 1Password Connect
384-
Parameters:
385-
url: The url of the 1Password Connect API
386-
token: The 1Password Service Account token
393+
394+
Args:
395+
url: The url of the 1Password Connect API
396+
token: The 1Password Service Account token
397+
**kwargs: Additional httpx.Client configuration options
387398
388399
Returns:
389-
Client: The 1Password Connect client
400+
Client: The 1Password Connect client
390401
"""
391-
return Client(url, token)
402+
from onepasswordconnectsdk.config import ClientConfig
403+
config = ClientConfig(url=url, token=token, **kwargs)
404+
return Client(config)
392405

393406

394-
def new_client_from_environment(url: str = None) -> Client:
407+
def new_client_from_environment(url: str = None, **kwargs) -> Client:
395408
"""Builds a new client for interacting with 1Password Connect
396409
using the OP_CONNECT_TOKEN environment variable
397410
398-
Parameters:
399-
url: The url of the 1Password Connect API
411+
Args:
412+
url: The url of the 1Password Connect API
413+
**kwargs: Additional httpx.Client configuration options
400414
401415
Returns:
402-
Client: The 1Password Connect client
416+
Client: The 1Password Connect client
403417
"""
404418
token = os.environ.get(ENV_SERVICE_ACCOUNT_JWT_VARIABLE)
405419

@@ -416,4 +430,4 @@ def new_client_from_environment(url: str = None) -> Client:
416430
f"{ENV_SERVICE_ACCOUNT_JWT_VARIABLE} variable"
417431
)
418432

419-
return new_client(url, token)
433+
return new_client(url, token, certificate, **kwargs)

0 commit comments

Comments
 (0)