Skip to content

Commit e482e93

Browse files
committed
update readme
1 parent 28d5d4a commit e482e93

File tree

1 file changed

+3
-356
lines changed

1 file changed

+3
-356
lines changed

README.md

Lines changed: 3 additions & 356 deletions
Original file line numberDiff line numberDiff line change
@@ -1,362 +1,9 @@
11
# Codex Python API library
22

3-
[![PyPI version](https://img.shields.io/pypi/v/codex.svg)](https://pypi.org/project/codex/)
3+
# Installation
44

5-
The Codex Python library provides convenient access to the Codex REST API from any Python 3.8+
6-
application. The library includes type definitions for all request params and response fields,
7-
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
8-
9-
It is generated with [Stainless](https://www.stainlessapi.com/).
10-
11-
## Documentation
12-
13-
The REST API documentation can be found on [help.cleanlab.ai](https://help.cleanlab.ai). The full API of this library can be found in [api.md](api.md).
14-
15-
## Installation
16-
17-
```sh
18-
# install from this staging repo
19-
pip install git+ssh://[email protected]/stainless-sdks/codex-python.git
20-
```
21-
22-
> [!NOTE]
23-
> Once this package is [published to PyPI](https://app.stainlessapi.com/docs/guides/publish), this will become: `pip install --pre codex`
24-
25-
## Usage
26-
27-
The full API of this library can be found in [api.md](api.md).
28-
29-
```python
30-
from codex import Codex
31-
32-
client = Codex(
33-
# or 'production' | 'local'; defaults to "production".
34-
environment="staging",
35-
)
36-
37-
project_return_schema = client.projects.create(
38-
config={},
39-
name="name",
40-
organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
41-
)
42-
print(project_return_schema.id)
43-
```
44-
45-
While you can provide a `bearer_token` keyword argument,
46-
we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
47-
to add `BEARER_TOKEN="My Bearer Token"` to your `.env` file
48-
so that your Bearer Token is not stored in source control.
49-
50-
## Async usage
51-
52-
Simply import `AsyncCodex` instead of `Codex` and use `await` with each API call:
53-
54-
```python
55-
import asyncio
56-
from codex import AsyncCodex
57-
58-
client = AsyncCodex(
59-
# or 'production' | 'local'; defaults to "production".
60-
environment="staging",
61-
)
62-
63-
64-
async def main() -> None:
65-
project_return_schema = await client.projects.create(
66-
config={},
67-
name="name",
68-
organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
69-
)
70-
print(project_return_schema.id)
71-
72-
73-
asyncio.run(main())
74-
```
75-
76-
Functionality between the synchronous and asynchronous clients is otherwise identical.
77-
78-
## Using types
79-
80-
Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
81-
82-
- Serializing back into JSON, `model.to_json()`
83-
- Converting to a dictionary, `model.to_dict()`
84-
85-
Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.
86-
87-
## Handling errors
88-
89-
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `codex.APIConnectionError` is raised.
90-
91-
When the API returns a non-success status code (that is, 4xx or 5xx
92-
response), a subclass of `codex.APIStatusError` is raised, containing `status_code` and `response` properties.
93-
94-
All errors inherit from `codex.APIError`.
95-
96-
```python
97-
import codex
98-
from codex import Codex
99-
100-
client = Codex()
101-
102-
try:
103-
client.projects.create(
104-
config={},
105-
name="name",
106-
organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
107-
)
108-
except codex.APIConnectionError as e:
109-
print("The server could not be reached")
110-
print(e.__cause__) # an underlying Exception, likely raised within httpx.
111-
except codex.RateLimitError as e:
112-
print("A 429 status code was received; we should back off a bit.")
113-
except codex.APIStatusError as e:
114-
print("Another non-200-range status code was received")
115-
print(e.status_code)
116-
print(e.response)
117-
```
118-
119-
Error codes are as follows:
120-
121-
| Status Code | Error Type |
122-
| ----------- | -------------------------- |
123-
| 400 | `BadRequestError` |
124-
| 401 | `AuthenticationError` |
125-
| 403 | `PermissionDeniedError` |
126-
| 404 | `NotFoundError` |
127-
| 422 | `UnprocessableEntityError` |
128-
| 429 | `RateLimitError` |
129-
| >=500 | `InternalServerError` |
130-
| N/A | `APIConnectionError` |
131-
132-
### Retries
133-
134-
Certain errors are automatically retried 2 times by default, with a short exponential backoff.
135-
Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
136-
429 Rate Limit, and >=500 Internal errors are all retried by default.
137-
138-
You can use the `max_retries` option to configure or disable retry settings:
139-
140-
```python
141-
from codex import Codex
142-
143-
# Configure the default for all requests:
144-
client = Codex(
145-
# default is 2
146-
max_retries=0,
147-
)
148-
149-
# Or, configure per-request:
150-
client.with_options(max_retries=5).projects.create(
151-
config={},
152-
name="name",
153-
organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
154-
)
155-
```
156-
157-
### Timeouts
158-
159-
By default requests time out after 1 minute. You can configure this with a `timeout` option,
160-
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
5+
You can install the Codex python client from [our internal repo](https://github.com/cleanlab/codex-python) with:
1616

1627
```python
163-
from codex import Codex
164-
165-
# Configure the default for all requests:
166-
client = Codex(
167-
# 20 seconds (default is 1 minute)
168-
timeout=20.0,
169-
)
170-
171-
# More granular control:
172-
client = Codex(
173-
timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
174-
)
175-
176-
# Override per-request:
177-
client.with_options(timeout=5.0).projects.create(
178-
config={},
179-
name="name",
180-
organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
181-
)
182-
```
183-
184-
On timeout, an `APITimeoutError` is thrown.
185-
186-
Note that requests that time out are [retried twice by default](#retries).
187-
188-
## Advanced
189-
190-
### Logging
191-
192-
We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.
193-
194-
You can enable logging by setting the environment variable `CODEX_LOG` to `info`.
195-
196-
```shell
197-
$ export CODEX_LOG=info
8+
pip install git+ssh://git@github.com/cleanlab/codex-python.git
1989
```
199-
200-
Or to `debug` for more verbose logging.
201-
202-
### How to tell whether `None` means `null` or missing
203-
204-
In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:
205-
206-
```py
207-
if response.my_field is None:
208-
if 'my_field' not in response.model_fields_set:
209-
print('Got json like {}, without a "my_field" key present at all.')
210-
else:
211-
print('Got json like {"my_field": null}.')
212-
```
213-
214-
### Accessing raw response data (e.g. headers)
215-
216-
The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,
217-
218-
```py
219-
from codex import Codex
220-
221-
client = Codex()
222-
response = client.projects.with_raw_response.create(
223-
config={},
224-
name="name",
225-
organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
226-
)
227-
print(response.headers.get('X-My-Header'))
228-
229-
project = response.parse() # get the object that `projects.create()` would have returned
230-
print(project.id)
231-
```
232-
233-
These methods return an [`APIResponse`](https://github.com/stainless-sdks/codex-python/tree/main/src/codex/_response.py) object.
234-
235-
The async client returns an [`AsyncAPIResponse`](https://github.com/stainless-sdks/codex-python/tree/main/src/codex/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.
236-
237-
#### `.with_streaming_response`
238-
239-
The above interface eagerly reads the full response body when you make the request, which may not always be what you want.
240-
241-
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.
242-
243-
```python
244-
with client.projects.with_streaming_response.create(
245-
config={},
246-
name="name",
247-
organization_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
248-
) as response:
249-
print(response.headers.get("X-My-Header"))
250-
251-
for line in response.iter_lines():
252-
print(line)
253-
```
254-
255-
The context manager is required so that the response will reliably be closed.
256-
257-
### Making custom/undocumented requests
258-
259-
This library is typed for convenient access to the documented API.
260-
261-
If you need to access undocumented endpoints, params, or response properties, the library can still be used.
262-
263-
#### Undocumented endpoints
264-
265-
To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other
266-
http verbs. Options on the client will be respected (such as retries) when making this request.
267-
268-
```py
269-
import httpx
270-
271-
response = client.post(
272-
"/foo",
273-
cast_to=httpx.Response,
274-
body={"my_param": True},
275-
)
276-
277-
print(response.headers.get("x-foo"))
278-
```
279-
280-
#### Undocumented request params
281-
282-
If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request
283-
options.
284-
285-
#### Undocumented response properties
286-
287-
To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You
288-
can also get all the extra fields on the Pydantic model as a dict with
289-
[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).
290-
291-
### Configuring the HTTP client
292-
293-
You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
294-
295-
- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)
296-
- Custom [transports](https://www.python-httpx.org/advanced/transports/)
297-
- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality
298-
299-
```python
300-
import httpx
301-
from codex import Codex, DefaultHttpxClient
302-
303-
client = Codex(
304-
# Or use the `CODEX_BASE_URL` env var
305-
base_url="http://my.test.server.example.com:8083",
306-
http_client=DefaultHttpxClient(
307-
proxy="http://my.test.proxy.example.com",
308-
transport=httpx.HTTPTransport(local_address="0.0.0.0"),
309-
),
310-
)
311-
```
312-
313-
You can also customize the client on a per-request basis by using `with_options()`:
314-
315-
```python
316-
client.with_options(http_client=DefaultHttpxClient(...))
317-
```
318-
319-
### Managing HTTP resources
320-
321-
By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.
322-
323-
```py
324-
from codex import Codex
325-
326-
with Codex() as client:
327-
# make requests here
328-
...
329-
330-
# HTTP client is now closed
331-
```
332-
333-
## Versioning
334-
335-
This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
336-
337-
1. Changes that only affect static types, without breaking runtime behavior.
338-
2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_
339-
3. Changes that we do not expect to impact the vast majority of users in practice.
340-
341-
We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
342-
343-
We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/codex-python/issues) with questions, bugs, or suggestions.
344-
345-
### Determining the installed version
346-
347-
If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version.
348-
349-
You can determine the version that is being used at runtime with:
350-
351-
```py
352-
import codex
353-
print(codex.__version__)
354-
```
355-
356-
## Requirements
357-
358-
Python 3.8 or higher.
359-
360-
## Contributing
361-
362-
See [the contributing documentation](./CONTRIBUTING.md).

0 commit comments

Comments
 (0)