lothc 0.0.1__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.
Files changed (67) hide show
  1. lothc-0.0.1/.github/workflows/ci.yml +23 -0
  2. lothc-0.0.1/.github/workflows/docs.yml +29 -0
  3. lothc-0.0.1/.github/workflows/release.yml +57 -0
  4. lothc-0.0.1/.gitignore +29 -0
  5. lothc-0.0.1/.pre-commit-config.yaml +52 -0
  6. lothc-0.0.1/AGENTS.md +77 -0
  7. lothc-0.0.1/CLAUDE.md +427 -0
  8. lothc-0.0.1/LICENSE +21 -0
  9. lothc-0.0.1/PKG-INFO +106 -0
  10. lothc-0.0.1/README.md +81 -0
  11. lothc-0.0.1/Taskfile.yml +225 -0
  12. lothc-0.0.1/assets/favicon-ring.svg +89 -0
  13. lothc-0.0.1/assets/logo.svg +97 -0
  14. lothc-0.0.1/assets/perf-race.svg +214 -0
  15. lothc-0.0.1/asv.conf.json +22 -0
  16. lothc-0.0.1/asv_bench/__init__.py +0 -0
  17. lothc-0.0.1/asv_bench/_quick_check_worker.py +59 -0
  18. lothc-0.0.1/asv_bench/bench_download.py +113 -0
  19. lothc-0.0.1/asv_bench/bench_verbs.py +117 -0
  20. lothc-0.0.1/asv_bench/quick_check.py +137 -0
  21. lothc-0.0.1/benchmarks/Dockerfile +45 -0
  22. lothc-0.0.1/benchmarks/docker-compose.yml +24 -0
  23. lothc-0.0.1/benchmarks/entrypoint.sh +15 -0
  24. lothc-0.0.1/benchmarks/json_server/Cargo.toml +9 -0
  25. lothc-0.0.1/benchmarks/json_server/src/main.rs +60 -0
  26. lothc-0.0.1/benchmarks/race_svg.py +212 -0
  27. lothc-0.0.1/docs/assets/logo-dark.svg +97 -0
  28. lothc-0.0.1/docs/assets/logo-light.svg +97 -0
  29. lothc-0.0.1/docs/assets/perf-race.svg +1 -0
  30. lothc-0.0.1/docs/auth.md +63 -0
  31. lothc-0.0.1/docs/benchmarks.md +55 -0
  32. lothc-0.0.1/docs/development.md +15 -0
  33. lothc-0.0.1/docs/errors.md +31 -0
  34. lothc-0.0.1/docs/favicon.ico +0 -0
  35. lothc-0.0.1/docs/images/lothc-favicon.png +0 -0
  36. lothc-0.0.1/docs/index.md +190 -0
  37. lothc-0.0.1/docs/networking.md +16 -0
  38. lothc-0.0.1/docs/retries.md +26 -0
  39. lothc-0.0.1/docs/sse.md +185 -0
  40. lothc-0.0.1/docs/streaming.md +75 -0
  41. lothc-0.0.1/docs/stylesheets/extra.css +15 -0
  42. lothc-0.0.1/docs/verbs.md +143 -0
  43. lothc-0.0.1/examples/server.py +26 -0
  44. lothc-0.0.1/lothc/__init__.py +41 -0
  45. lothc-0.0.1/lothc/_client.py +1967 -0
  46. lothc-0.0.1/lothc/_compat.py +35 -0
  47. lothc-0.0.1/lothc/py.typed +0 -0
  48. lothc-0.0.1/perf.py +648 -0
  49. lothc-0.0.1/pyproject.toml +210 -0
  50. lothc-0.0.1/style-guide.md +365 -0
  51. lothc-0.0.1/tests/_server.py +261 -0
  52. lothc-0.0.1/tests/conftest.py +29 -0
  53. lothc-0.0.1/tests/test_auth.py +33 -0
  54. lothc-0.0.1/tests/test_cookies.py +17 -0
  55. lothc-0.0.1/tests/test_delete_head.py +34 -0
  56. lothc-0.0.1/tests/test_download.py +57 -0
  57. lothc-0.0.1/tests/test_get.py +122 -0
  58. lothc-0.0.1/tests/test_get_result.py +33 -0
  59. lothc-0.0.1/tests/test_redirects.py +16 -0
  60. lothc-0.0.1/tests/test_retries.py +66 -0
  61. lothc-0.0.1/tests/test_sse.py +76 -0
  62. lothc-0.0.1/tests/test_streaming.py +58 -0
  63. lothc-0.0.1/tests/test_transport_errors.py +24 -0
  64. lothc-0.0.1/tests/test_write.py +102 -0
  65. lothc-0.0.1/uv.lock +1938 -0
  66. lothc-0.0.1/vulture_whitelist.py +3 -0
  67. lothc-0.0.1/zensical.toml +126 -0
@@ -0,0 +1,23 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ pull_request:
7
+ jobs:
8
+ test:
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ python-version: ["3.13", "3.14"]
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ - uses: astral-sh/setup-uv@v10.0.1
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - run: uv sync --all-extras --group dev
20
+ - run: uv run ruff check .
21
+ - run: uv run ruff format --check .
22
+ - run: uv run basedpyright .
23
+ - run: uv run pytest tests
@@ -0,0 +1,29 @@
1
+ name: Documentation
2
+ on:
3
+ push:
4
+ branches:
5
+ - master
6
+ - main
7
+ permissions:
8
+ contents: read
9
+ pages: write
10
+ id-token: write
11
+ jobs:
12
+ deploy:
13
+ environment:
14
+ name: github-pages
15
+ url: ${{ steps.deployment.outputs.page_url }}
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/configure-pages@v6
19
+ - uses: actions/checkout@v7
20
+ - uses: actions/setup-python@v6
21
+ with:
22
+ python-version: 3.x
23
+ - run: pip install zensical
24
+ - run: zensical build --clean
25
+ - uses: actions/upload-pages-artifact@v5
26
+ with:
27
+ path: site
28
+ - uses: actions/deploy-pages@v5
29
+ id: deployment
@@ -0,0 +1,57 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ # Trusted Publishing (OIDC) — no PyPI token/secret needed. The environment name here must
11
+ # match the one configured as the trusted publisher on the PyPI project settings ("pypi").
12
+ environment:
13
+ name: pypi
14
+ url: https://pypi.org/p/lothc
15
+ permissions:
16
+ id-token: write
17
+ steps:
18
+ - uses: actions/checkout@v7
19
+ with:
20
+ # hatch-vcs derives the version from git tags — needs full history to see them,
21
+ # not just the single commit a shallow checkout would give it.
22
+ fetch-depth: 0
23
+
24
+ - uses: astral-sh/setup-uv@v10.0.1
25
+ with:
26
+ python-version: "3.13"
27
+
28
+ - run: uv build
29
+
30
+ - run: uv publish
31
+
32
+ deploy-docs:
33
+ needs: publish
34
+ runs-on: ubuntu-latest
35
+ permissions:
36
+ contents: read
37
+ pages: write
38
+ id-token: write
39
+ environment:
40
+ name: github-pages
41
+ url: ${{ steps.deployment.outputs.page_url }}
42
+ steps:
43
+ - uses: actions/checkout@v7
44
+
45
+ - uses: astral-sh/setup-uv@v10.0.1
46
+ with:
47
+ python-version: "3.13"
48
+
49
+ - run: uv sync --group docs
50
+ - run: uv run zensical build
51
+
52
+ - uses: actions/upload-pages-artifact@v5
53
+ with:
54
+ path: site
55
+
56
+ - id: deployment
57
+ uses: actions/deploy-pages@v5
lothc-0.0.1/.gitignore ADDED
@@ -0,0 +1,29 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ .ruff_cache/
5
+ .pytest_cache/
6
+ .coverage
7
+ htmlcov/
8
+ dist/
9
+ *.egg-info/
10
+ .DS_Store
11
+
12
+ # Handy for temporary run scripts
13
+ tmp_*.py
14
+ run_*.py
15
+
16
+ # Local environment and scratch input files
17
+ .env
18
+ .in
19
+
20
+ # perf.py run output (JSON per run, named by ms-timestamp run id)
21
+ /results/
22
+
23
+ # zensical docs build output
24
+ /site/
25
+
26
+ # asv (airspeed velocity) benchmark environments/results/generated test data
27
+ /.asv/
28
+ /asv_bench/_data/
29
+ /asv_bench/.quick_check_history.json
@@ -0,0 +1,52 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-toml
9
+ - id: check-added-large-files
10
+ - id: check-merge-conflict
11
+
12
+ - repo: local
13
+ hooks:
14
+ - id: ruff-check
15
+ name: ruff check
16
+ entry: uv run ruff check --fix
17
+ language: system
18
+ types: [python]
19
+
20
+ - id: ruff-format
21
+ name: ruff format
22
+ entry: uv run ruff format
23
+ language: system
24
+ types: [python]
25
+
26
+ - id: basedpyright
27
+ name: basedpyright
28
+ entry: uv run basedpyright .
29
+ language: system
30
+ files: \.py$
31
+ pass_filenames: false
32
+
33
+ - id: deptry
34
+ name: deptry
35
+ entry: uv run deptry .
36
+ language: system
37
+ files: \.py$
38
+ pass_filenames: false
39
+
40
+ - id: vulture
41
+ name: vulture
42
+ entry: uv run vulture --min-confidence 100 lothc tests examples benchmarks perf.py vulture_whitelist.py
43
+ language: system
44
+ files: \.py$
45
+ pass_filenames: false
46
+
47
+ - id: pylint
48
+ name: pylint
49
+ entry: uv run pylint lothc
50
+ language: system
51
+ files: \.py$
52
+ pass_filenames: false
lothc-0.0.1/AGENTS.md ADDED
@@ -0,0 +1,77 @@
1
+ # lothc — agent reference
2
+
3
+ Typed HTTP client on pyreqwest. `HTTPClient` (async) / `SyncHTTPClient` (sync) — identical API,
4
+ mirror methods 1:1 (drop `await`, `async with` → `with`, async iterators → sync iterators).
5
+
6
+ ## Build
7
+
8
+ ```python
9
+ async with HTTPClient.build(
10
+ base_url=None,
11
+ bearer_token=None,
12
+ bearer_auth=None,
13
+ default_headers=None,
14
+ timeout=30.0,
15
+ cookie_store=False,
16
+ follow_redirects=True,
17
+ max_redirects=None,
18
+ proxy=None,
19
+ max_retries=0,
20
+ retry_methods=None,
21
+ ) as client:
22
+ ...
23
+ ```
24
+
25
+ `bearer_token: str` (static) xor `bearer_auth: Callable[[], Awaitable[str]]` (sync client:
26
+ `Callable[[], str]`) — resolved fresh per request, at most one of the two. `default_headers`
27
+ sent on every request. `cookie_store=True` = in-memory jar. `proxy: str | None`.
28
+
29
+ ## Decode targets (`response_data_type`, default `bytes`)
30
+
31
+ - `bytes` — raw, default
32
+ - `lothc.JSON` — `dict[str, Any]` subclass, zero validation
33
+ - pydantic `BaseModel` subclass
34
+ - msgspec `Struct` subclass
35
+ - `TypedDict` subclass — validated via typeguard if installed, else warns once
36
+ (`LOTHC_SUPPRESS_TYPEGUARD_WARNING=1` to silence)
37
+ - bare `dict` / `dict[str, Any]` — NOT allowed, raises `TypeError`
38
+
39
+ ## Verbs
40
+
41
+ - `get(path, *, params=None, headers=None, response_data_type=bytes, error_for_status=True) -> Data`
42
+ - `get_result(path, *, params=None, headers=None, response_data_type=bytes, headers_type=None, error_for_status=True) -> Result` —
43
+ `.data .status .headers .typed_headers`
44
+ - `post/put/patch(path, *, params=None, headers=None, json=None, form=None, content=None, response_data_type=bytes, error_for_status=True) -> Data` —
45
+ at most one of `json`/`form`/`content`, else `ValueError`
46
+ - `delete(path, *, params=None, headers=None, response_data_type=bytes, error_for_status=True) -> Data`
47
+ - `head(path, *, params=None, headers=None, headers_type=None, error_for_status=True) -> Result[None]`
48
+ - `sse(path, *, params=None, headers=None, response_data_type=None, id_type=str, error_for_status=True) -> Iterator[SSEEvent[TData, TId]]` —
49
+ always yields `SSEEvent(id=, event=, data=)` (kw-only, `SSEEvent[TData, TId=str]`).
50
+ `response_data_type` controls `.data`'s type only (default `str`); class | pydantic
51
+ `TypeAdapter` | msgspec `Decoder`. `.event` is always `str`, never `None` (spec defaults it to
52
+ `"message"` when absent from the wire). `.id` is genuinely `str | None` per spec — `id_type` is
53
+ the single knob for both requiredness and type: `str` (default, required, no coercion) | any
54
+ other bare type e.g. `int`/`uuid.UUID` (required, coerced via `id_type(raw)`) | that type
55
+ unioned with `None` e.g. `int | None` (optional, coerced when present, `None` when absent) |
56
+ bare `None` (optional, `.id: str | None`, never coerced) — pass a union the same way you'd
57
+ write `response_data_type=A | B` for a discriminated union, `TId` binds to whatever you pass
58
+ - `stream_get(path, *, params=None, headers=None, response_data_type=None, error_for_status=True) -> Iterator[bytes | TLine]` —
59
+ raw unbuffered bytes by default (safe for binary); `response_data_type` switches to
60
+ newline-buffered per-line decode
61
+ - `stream_post(path, *, params=None, headers=None, json=None, form=None, content=None, response_data_type=None, error_for_status=True) -> Iterator[bytes | TLine]`
62
+
63
+ `params`/`headers`: `dict`/`Mapping[str, str]`, or `BaseModel`/`Struct` (`None` fields omitted).
64
+ `json`: `dict` | `BaseModel` | `Struct`. `form`: `dict[str, int | bytes | str | File]`, `File =
65
+ tuple[str, bytes] | Path | BufferedIOBase`. `content`: raw `str | bytes` body.
66
+
67
+ ## Errors
68
+
69
+ - `ResponseError(status, body_start)` — 4xx/5xx, raised when `error_for_status=True` (default)
70
+ - `TransportError` base; `TimeoutError`, `ConnectionError` subclasses — no response received
71
+ - pydantic/msgspec/typeguard validation errors propagate unwrapped (not translated)
72
+
73
+ ## Retries
74
+
75
+ `max_retries` (default `0` = off), `retry_methods` (default `{GET,PUT,DELETE,HEAD}` — `POST`/
76
+ `PATCH` need explicit opt-in). Exponential backoff; retries on transport error or status in
77
+ `{429,500,502,503,504}`; honors `Retry-After`.