Skip to content

Commit ace9057

Browse files
OmarAlJarrahclaude
andcommitted
docs: refresh CLAUDE.md to match the current workspace
- Layout: document all five packages (httpx, aiohttp, requests joined stdlib), the core config/ and util/ subpackages, the expanded auth pillar (challenge handlers, digest, token cache), and the staged pipeline internals; drop the stale 'planned follow-up packages' note - Architecture: replace the provisional RetryableStep / M2 / to-implement.md paragraph with the shipped Policy + Stage + StagedPipelineBuilder design - CI note: python matrix is now 3.8-3.13 - Conventions: record the MIT licence header required on every .py file Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent cae63c3 commit ace9057

1 file changed

Lines changed: 67 additions & 41 deletions

File tree

‎CLAUDE.md‎

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ bodies are modelled as typed Pythonic abstractions instead.
2323
- **`mypy --strict` clean.** Every public signature is typed; no `Any` in
2424
public API; no unused `# type: ignore` comments.
2525
- **`ruff` and `ruff format` clean** (rule set in `pyproject.toml`).
26-
- **No runtime dependencies.** `core` ships against the standard library only.
27-
If you reach for a third-party package, stop — model it as an adapter
28-
behind `HttpClient` or `Serde`.
26+
- **No runtime dependencies, with one sanctioned exception: `furl`.** `core`
27+
otherwise ships against the standard library only. `furl` powers
28+
`http.common.Url` parse/serialise; do not introduce any other third-party
29+
runtime dep — model it as an adapter behind `HttpClient` or `Serde` instead.
2930
- **Immutable data with slots.** Models are
3031
`@dataclass(frozen=True, slots=True)`; mutate via `dataclasses.replace` or
3132
the `with_*` helpers. Builders are a Java idiom — Python's keyword and
@@ -64,26 +65,37 @@ bodies are modelled as typed Pythonic abstractions instead.
6465
- **Function-size cap: 50 lines.** Aim 10–25. Refactor when you push past.
6566
- **Commit style:** `chore:` for refactors/cleanup; `feat:` for new features;
6667
`fix:` for bug fixes; `docs:` for documentation-only changes.
68+
- **MIT licence header on every `.py` file.** The project is MIT-licensed
69+
(`LICENSE.md` at the root and in each package). Every Python source file —
70+
src and tests alike — starts with the two-line header before the module
71+
docstring:
72+
73+
```python
74+
# Copyright (c) 2026 dexpace and Omar Aljarrah.
75+
# Licensed under the MIT License. See LICENSE.md in the repository root for details.
76+
```
6777

6878
## Repository Layout
6979

70-
The repo is a `uv`-managed workspace. Each member under `packages/` is its own
71-
distribution; PEP 420 namespace packages let them share the `dexpace.sdk.*`
72-
prefix. Commands run from the workspace root via `uv run …` — `uv sync`
73-
provisions the virtualenv with both packages installed in editable mode.
80+
The repo is a `uv`-managed workspace of five distributions. Each member under
81+
`packages/` is its own distribution; PEP 420 namespace packages let them share
82+
the `dexpace.sdk.*` prefix. Commands run from the workspace root via
83+
`uv run …` — `uv sync` provisions the virtualenv with all packages installed
84+
in editable mode.
7485

7586
```
7687
python-sdk/
77-
├── LICENSE.md
88+
├── LICENSE.md # MIT (also copied into each package)
7889
├── README.md
7990
├── CLAUDE.md
8091
├── pyproject.toml # workspace root (uv workspace, dev deps,
8192
│ # ruff/mypy/pytest config)
8293
├── uv.lock
83-
├── .github/workflows/ci.yml # pytest + mypy + ruff on 3.12 and 3.13
84-
├── docs/ # cross-package documentation
94+
├── .github/workflows/ci.yml # pytest + mypy + ruff, python matrix 3.8–3.13
95+
├── docs/ # cross-package documentation: architecture,
96+
│ # auth, bodies, errors, http, pipelines
8597
└── packages/
86-
├── dexpace-sdk-core/ # zero-dependency toolkit (no transports)
98+
├── dexpace-sdk-core/ # toolkit (no transports); only runtime dep: furl
8799
│ ├── pyproject.toml
88100
│ ├── README.md
89101
│ ├── src/dexpace/sdk/core/
@@ -99,40 +111,49 @@ python-sdk/
99111
│ │ │ ├── context/ # CallContext, DispatchContext,
100112
│ │ │ │ # RequestContext, ExchangeContext,
101113
│ │ │ │ # ContextStore
102-
│ │ │ └── auth/ # Credential, BearerTokenPolicy,
103-
│ │ │ # BasicAuthPolicy, KeyCredentialPolicy
104-
│ │ ├── pipeline/ # Pipeline, Policy ABC, RetryPolicy,
105-
│ │ │ # LoggingPolicy, TracingPolicy, async twins
114+
│ │ │ └── auth/ # TokenCredential, BearerTokenPolicy,
115+
│ │ │ # BasicAuthPolicy, KeyCredentialPolicy,
116+
│ │ │ # ChallengeHandler (Basic/Digest/Composite),
117+
│ │ │ # AuthenticateChallenge, TokenCache
118+
│ │ ├── pipeline/ # Pipeline/AsyncPipeline, Policy/AsyncPolicy,
119+
│ │ │ │ # Stage, StagedPipelineBuilder, defaults,
120+
│ │ │ │ # sans-io + transport runners under the hood
121+
│ │ │ │
122+
│ │ │ ├── policies/ # retry, redirect, logging, tracing,
123+
│ │ │ │ # set_date (+ async twins)
124+
│ │ │ └── step/ # PipelineStep, StepMetadata, RetryConfig
106125
│ │ ├── client/ # HttpClient + AsyncHttpClient Protocols
126+
│ │ ├── config/ # Configuration
107127
│ │ ├── serde/ # Serde, Serializer, Deserializer Protocols
108128
│ │ ├── errors/ # SDK-level exception hierarchy
109-
│ │ └── instrumentation/ # InstrumentationContext, Span, Tracer,
110-
│ │ # TracingScope, noops
111-
│ └── tests/ # pytest suite — http/, context/,
112-
│ # pipeline/, auth/, serde/, sse/, errors/,
113-
│ # instrumentation/
114-
└── dexpace-sdk-http-stdlib/ # reference stdlib transports
115-
├── pyproject.toml # depends on dexpace-sdk-core
116-
├── README.md
117-
├── src/dexpace/sdk/http/stdlib/
118-
│ ├── urllib_http_client.py # UrllibHttpClient (sync, blocking)
119-
│ └── asyncio_http_client.py # AsyncioHttpClient (async, stdlib only)
120-
└── tests/
129+
│ │ ├── instrumentation/ # InstrumentationContext, Span, Tracer,
130+
│ │ │ # TracingScope, noops
131+
│ │ └── util/ # clock, proxy helpers
132+
│ └── tests/ # pytest suite — auth/, config/, context/,
133+
│ # errors/, http/, instrumentation/,
134+
│ # pipeline/, serde/, sse/, util/
135+
├── dexpace-sdk-http-stdlib/ # reference stdlib transports:
136+
│ │ # UrllibHttpClient, AsyncioHttpClient
137+
│ └── src/dexpace/sdk/http/stdlib/
138+
├── dexpace-sdk-http-httpx/ # httpx transports (sync + async)
139+
│ └── src/dexpace/sdk/http/httpx/
140+
├── dexpace-sdk-http-aiohttp/ # aiohttp transport (async)
141+
│ └── src/dexpace/sdk/http/aiohttp/
142+
└── dexpace-sdk-http-requests/ # requests transport (sync)
143+
└── src/dexpace/sdk/http/requests/
121144
```
122145

123-
Planned follow-up packages (not yet present): `dexpace-sdk-http-httpx`,
124-
`dexpace-sdk-http-aiohttp`, `dexpace-sdk-http-requests`. Each will live under
125-
`packages/` as a separate distribution, depend on `dexpace-sdk-core`, and
126-
adapt its third-party HTTP library to the `HttpClient` / `AsyncHttpClient`
127-
Protocols. Namespace packaging (no `__init__.py` at `src/dexpace/`,
128-
`src/dexpace/sdk/`, or `src/dexpace/sdk/http/`) is mandatory for every
129-
package so the `dexpace.sdk` prefix stays shared.
146+
Every transport package depends on `dexpace-sdk-core` and adapts its HTTP
147+
library to the `HttpClient` / `AsyncHttpClient` Protocols. Namespace
148+
packaging (no `__init__.py` at `src/dexpace/`, `src/dexpace/sdk/`, or
149+
`src/dexpace/sdk/http/`) is mandatory for every package so the `dexpace.sdk`
150+
prefix stays shared.
130151

131152
### Common commands (run from the workspace root)
132153

133154
```bash
134155
uv sync # install workspace + dev tools
135-
uv run pytest -q # walk both packages' test suites
156+
uv run pytest -q # walk all five packages' test suites
136157
uv run mypy --strict # type-check everything in `files = [...]`
137158
uv run ruff check # lint
138159
uv run ruff format --check # formatting gate
@@ -162,13 +183,18 @@ Layered, bottom-up:
162183
→ `ExchangeContext`, all carrying an `InstrumentationContext` for tracing
163184
correlation. The thread-safe `ContextStore` is keyed by trace id; entries
164185
evict on `CallContext.close()`.
165-
4. **`pipeline/step/PipelineStep`** — a Protocol with signature
166-
`(input, context) -> output`. Steps compose into chains; the provisional
167-
`RetryableStep` adds a retry hook (M2 replaces it with a `Policy` ABC
168-
that wraps the downstream chain — see `to-implement.md`). `StepMetadata`
169-
and `RetryConfig` provide optional configuration.
186+
4. **`pipeline`** — `Policy` (and `AsyncPolicy`) wrap the downstream chain;
187+
`Pipeline` / `AsyncPipeline` run an ordered set of policies grouped into
188+
`Stage`s via `StagedPipelineBuilder`. Shipped policies: retry, redirect,
189+
logging, tracing, set-date (each with an async twin under
190+
`pipeline/policies/`). `default_pipeline()` / `default_async_pipeline()`
191+
assemble the standard stack. The lower-level `pipeline/step/PipelineStep`
192+
Protocol (`(input, context) -> output`) plus `StepMetadata` / `RetryConfig`
193+
remain for custom composition.
170194
5. **`client/HttpClient`** — single-method Protocol
171-
(`execute(request) -> Response`). Transport is **not** provided by `core`.
195+
(`execute(request) -> Response`). Transport is **not** provided by `core`;
196+
the `dexpace-sdk-http-*` packages (stdlib, httpx, aiohttp, requests) each
197+
adapt one HTTP library to the Protocol.
172198

173199
## Things That Will Bite You
174200

0 commit comments

Comments
 (0)