Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
be81c75
feat!: align types and client with latest API spec
Kevin-layerV Mar 31, 2026
8ccdd69
fix: address review feedback — recursive serialization and dead code …
Kevin-layerV Mar 31, 2026
335aea3
fix: second review pass - simplify and harden serialization
Kevin-layerV Mar 31, 2026
c6bdb97
fix: add missing Args docstring to async list_all
Kevin-layerV Apr 7, 2026
cbbf501
merge: resolve conflicts with main (feat/v1-identity-fix)
justin-layerv Apr 10, 2026
3606340
fix: address all CR feedback — 6 issues across 5 review rounds
justin-layerv Apr 10, 2026
981ecde
fix: restore builtins.list for annotations inside class with list() m…
justin-layerv Apr 10, 2026
10799d9
fix: address remaining CR feedback — 6 items from 3 review rounds
justin-layerv Apr 10, 2026
21559a1
fix: document qurl_id vs resource_id, recurse dicts in serializer, te…
justin-layerv Apr 10, 2026
747f0f2
fix: E501 line too long — move comment above field
justin-layerv Apr 10, 2026
b0de389
Merge remote-tracking branch 'origin/main' into feat/align-api-v2
justin-layerv Apr 11, 2026
3b32bea
fix: port seam-audit fixes and review rounds from qurl-typescript #14
justin-layerv Apr 11, 2026
39891e0
ci: make mypy gate robust; add langchain-core to dev extras
justin-layerv Apr 11, 2026
c7c9ceb
fix: address latest review — batch shape guard, tests, docs, url check
justin-layerv Apr 11, 2026
3f4ed74
fix: address review — exports, retry tests, CI notify, shape-guard cl…
justin-layerv Apr 11, 2026
51e587a
fix: address review — safe repr, bool shape guard, docstring, type order
justin-layerv Apr 11, 2026
657a075
fix: address review — BatchCreateItem TypedDict, docs, softened errors
justin-layerv Apr 11, 2026
43c1981
fix: Quota.plan "unknown" sentinel + _serialize_value asymmetry test
justin-layerv Apr 11, 2026
a34696c
fix: address review — typed access_policy, arithmetic guard, docs
justin-layerv Apr 11, 2026
339c918
revert: drop pytest filterwarnings suppression on langchain-core warning
justin-layerv Apr 11, 2026
269568a
fix: address review — parse_quota alignment, quota test coverage
justin-layerv Apr 11, 2026
3a39f69
fix: address review — debug log, underscore-convention doc, wire tests
justin-layerv Apr 11, 2026
e97afd3
fix: address review — asymmetry doc, trimmed docstring, list_all filt…
justin-layerv Apr 11, 2026
ecbda46
fix: address review — shape guard error class, parser enforcement, tests
justin-layerv Apr 11, 2026
c22da2b
fix: address review — correct allow_statuses docstring, test null err…
justin-layerv Apr 11, 2026
c41c6a4
fix: address review — Retry-After HTTP-date comment + regression tests
justin-layerv Apr 11, 2026
85ebe44
test: add @pytest.mark.asyncio to test_async_post_does_not_retry_on_503
justin-layerv Apr 11, 2026
a1d468b
docs: explain status=0 SDK convention in batch shape-guard error
justin-layerv Apr 11, 2026
f2004f8
docs: trim accumulated comments + add 207 passthrough note + migratio…
justin-layerv Apr 11, 2026
73ada8a
fix: address review — JSON error handling on allow_statuses path + 7 …
justin-layerv Apr 11, 2026
f6d3967
test: address review — access_policy immutability invariant guards
justin-layerv Apr 11, 2026
ecb7913
fix: address review — defensive guards + limit validation + 13 tests
justin-layerv Apr 12, 2026
818919b
test: address review — datetime serialization integration test
justin-layerv Apr 12, 2026
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
63 changes: 55 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ jobs:
test:
runs-on: ubuntu-latest
strategy:
# Don't cancel sibling matrix legs if one fails — we want full
# visibility into which Python versions broke.
fail-fast: false
matrix:
python-version: ["3.10", "3.12", "3.13"]
steps:
Expand All @@ -22,18 +25,40 @@ jobs:
run: pip install -e ".[dev,langchain]"
- name: Lint
run: ruff check
- name: Type check
if: matrix.python-version == '3.12'
run: mypy src/
- name: Test
run: pytest tests/ -v

# ============================================================================
# TYPE CHECK - Dedicated mypy job
# ============================================================================
# Runs in its own job so the gate can't silently vanish if the test
# matrix is restructured. Pins to the minimum supported Python version
# (matching `python_version` in pyproject.toml) so the strictness stays
# aligned with what the SDK promises to consumers.
type-check:
name: Type check (mypy)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Python 3.10
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.10"
- name: Install dependencies
# Use the full dev+langchain extras so mypy sees the optional
# langchain integration's real types. Without langchain-core
# installed, mypy reports spurious errors about missing modules
# and unused type-ignore comments in src/layerv_qurl/langchain.py.
run: pip install -e ".[dev,langchain]"
- name: Run mypy
run: mypy src/

# ============================================================================
# NOTIFY - Send Slack notification on build completion
# ============================================================================
notify:
name: Notify
needs: [test]
needs: [test, type-check]
if: always() && github.event_name != 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
Expand All @@ -43,6 +68,7 @@ jobs:
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
TEST_RESULT: ${{ needs.test.result }}
TYPE_CHECK_RESULT: ${{ needs.type-check.result }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
# All github context moved to env to prevent script injection
# via crafted branch names or actor names containing shell metacharacters.
Expand Down Expand Up @@ -77,27 +103,46 @@ jobs:
*) TRIGGER_TEXT="$TRIGGER" ;;
esac

# Aggregate status across both gates (test matrix + mypy). A
# mypy failure is a red build even if every python matrix leg
# passed, so the Slack message must reflect the worst of the two.
if [[ "$TEST_RESULT" == "success" && "$TYPE_CHECK_RESULT" == "success" ]]; then
AGGREGATE="success"
elif [[ "$TEST_RESULT" == "failure" || "$TYPE_CHECK_RESULT" == "failure" ]]; then
AGGREGATE="failure"
elif [[ "$TEST_RESULT" == "cancelled" || "$TYPE_CHECK_RESULT" == "cancelled" ]]; then
AGGREGATE="cancelled"
else
AGGREGATE="incomplete"
fi

# Determine status
if [[ "$TEST_RESULT" == "success" ]]; then
if [[ "$AGGREGATE" == "success" ]]; then
COLOR="#36a64f"; EMOJI="white_check_mark"
HEADER="QURL Python SDK Build"; STATUS_TEXT="successful"
elif [[ "$TEST_RESULT" == "failure" ]]; then
elif [[ "$AGGREGATE" == "failure" ]]; then
COLOR="#dc3545"; EMOJI="x"
HEADER="QURL Python SDK Build"; STATUS_TEXT="failed"
elif [[ "$TEST_RESULT" == "cancelled" ]]; then
elif [[ "$AGGREGATE" == "cancelled" ]]; then
COLOR="#ffc107"; EMOJI="warning"
HEADER="QURL Python SDK Build"; STATUS_TEXT="cancelled"
else
COLOR="#ffc107"; EMOJI="warning"
HEADER="QURL Python SDK"; STATUS_TEXT="incomplete"
fi

# Determine test emoji
# Determine per-gate emoji so the Slack message shows which
# gate failed when the aggregate is red.
case "$TEST_RESULT" in
success) TEST_EMOJI=":white_check_mark:" ;;
failure) TEST_EMOJI=":x:" ;;
*) TEST_EMOJI=":warning:" ;;
esac
case "$TYPE_CHECK_RESULT" in
success) TYPE_CHECK_EMOJI=":white_check_mark:" ;;
failure) TYPE_CHECK_EMOJI=":x:" ;;
*) TYPE_CHECK_EMOJI=":warning:" ;;
esac

# Extract first line of commit message (safe for any content)
FIRST_LINE=$(echo "$COMMIT_MESSAGE" | head -n1 | cut -c1-100)
Expand All @@ -114,6 +159,7 @@ jobs:
--arg trigger "$TRIGGER_TEXT" \
--arg actor "$GH_ACTOR" \
--arg test_emoji "$TEST_EMOJI" \
--arg type_check_emoji "$TYPE_CHECK_EMOJI" \
--arg commit "$FIRST_LINE" \
--arg commit_url "$COMMIT_URL" \
--arg workflow_url "$WORKFLOW_URL" \
Expand All @@ -123,6 +169,7 @@ jobs:
{type: "mrkdwn", text: ("*Branch:*\n`\($branch)` (\($sha))")},
{type: "mrkdwn", text: ("*Trigger:*\n\($trigger) by \($actor)")},
{type: "mrkdwn", text: ("*Tests:*\n\($test_emoji)")},
{type: "mrkdwn", text: ("*Type check:*\n\($type_check_emoji)")},
{type: "mrkdwn", text: "*Python:*\n3.10, 3.12, 3.13"}
]},
{type: "section", text: {type: "mrkdwn", text: ("*Commit:* `\($commit)`")}},
Expand Down
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ dev = [
"respx>=0.22",
"ruff>=0.11",
"mypy>=1.14",
# Pull the optional langchain integration into the default dev install
# via the self-reference pattern. Single source of truth for the
# langchain-core version constraint lives in the `[langchain]` extra
# above — updating it once keeps dev and CI in lockstep. Without
# langchain-core, local mypy produces spurious errors about a missing
# module and an unused type-ignore in langchain.py.
"layerv-qurl[langchain]",
]

[project.urls]
Expand Down
14 changes: 14 additions & 0 deletions src/layerv_qurl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,20 @@
AccessGrant,
AccessPolicy,
AccessToken,
AIAgentPolicy,
BatchCreateItem,
BatchCreateOutput,
BatchItemError,
BatchItemResult,
CreateOutput,
ListOutput,
MintOutput,
Quota,
QuotaPlan,
QURLStatus,
RateLimits,
ResolveOutput,
TokenStatus,
Usage,
)

Expand All @@ -45,7 +52,14 @@
"ServerError",
"ValidationError",
# Types
"AIAgentPolicy",
"BatchCreateItem",
"BatchCreateOutput",
"BatchItemError",
"BatchItemResult",
"QuotaPlan",
"QURLStatus",
"TokenStatus",
"AccessGrant",
"AccessPolicy",
"AccessToken",
Expand Down
Loading
Loading