src-py-lib 0.1.2__tar.gz → 0.1.4__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 (35) hide show
  1. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/.github/workflows/ci.yml +1 -0
  2. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/.github/workflows/release.yml +30 -20
  3. src_py_lib-0.1.4/.github/workflows/validate.yml +280 -0
  4. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/AGENTS.md +4 -4
  5. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/PKG-INFO +1 -1
  6. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/pyproject.toml +1 -1
  7. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/__init__.py +1 -0
  8. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/sourcegraph.py +21 -5
  9. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/tests/test_logging_http_clients.py +46 -0
  10. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/uv.lock +1 -1
  11. src_py_lib-0.1.2/.github/workflows/validate.yml +0 -124
  12. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/.gitignore +0 -0
  13. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/.markdownlint-cli2.yaml +0 -0
  14. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/.python-version +0 -0
  15. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/LICENSE +0 -0
  16. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/README.md +0 -0
  17. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/SECURITY.md +0 -0
  18. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/renovate.json +0 -0
  19. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/__init__.py +0 -0
  20. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/github.py +0 -0
  21. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/google_sheets.py +0 -0
  22. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/graphql.py +0 -0
  23. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/linear.py +0 -0
  24. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/one_password.py +0 -0
  25. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/clients/slack.py +0 -0
  26. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/py.typed +0 -0
  27. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/utils/__init__.py +0 -0
  28. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/utils/config.py +0 -0
  29. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/utils/http.py +0 -0
  30. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/utils/json_cache.py +0 -0
  31. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/utils/json_types.py +0 -0
  32. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/utils/logging.py +0 -0
  33. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/src/src_py_lib/utils/tsv.py +0 -0
  34. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/tests/test_import.py +0 -0
  35. {src_py_lib-0.1.2 → src_py_lib-0.1.4}/tests/test_tsv.py +0 -0
@@ -5,6 +5,7 @@ on:
5
5
 
6
6
  permissions:
7
7
  contents: read
8
+ pull-requests: read
8
9
 
9
10
  concurrency:
10
11
  group: ci-${{ github.workflow }}-${{ github.ref }}
@@ -13,6 +13,7 @@ on:
13
13
 
14
14
  permissions:
15
15
  contents: write
16
+ pull-requests: read
16
17
 
17
18
  concurrency:
18
19
  group: release-${{ github.event.inputs.tag || github.ref_name }}
@@ -28,10 +29,10 @@ jobs:
28
29
  uses: ./.github/workflows/validate.yml
29
30
  with:
30
31
  ref: ${{ github.event.inputs.tag || github.ref }}
32
+ build-package: false
31
33
 
32
34
  wheel:
33
35
  name: Build wheel
34
- needs: validate
35
36
  runs-on: ubuntu-24.04
36
37
  env:
37
38
  IMPORT_NAME: src_py_lib
@@ -50,10 +51,9 @@ jobs:
50
51
  uses: actions/setup-python@v6
51
52
  with:
52
53
  python-version: ${{ env.PYTHON_VERSION }}
53
- cache: pip
54
54
 
55
55
  - name: Cache uv
56
- uses: actions/cache@v4
56
+ uses: actions/cache@v5
57
57
  with:
58
58
  path: ~/.cache/uv
59
59
  key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
@@ -61,9 +61,7 @@ jobs:
61
61
  uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-
62
62
 
63
63
  - name: Install build tools
64
- run: |
65
- python -m pip install --upgrade pip
66
- python -m pip install "uv==${UV_VERSION}"
64
+ run: python -m pip install "uv==${UV_VERSION}"
67
65
 
68
66
  - name: Validate release inputs
69
67
  id: release
@@ -145,7 +143,6 @@ jobs:
145
143
  run: |
146
144
  python -m venv build/release/install-venv
147
145
  . build/release/install-venv/bin/activate
148
- python -m pip install --upgrade pip
149
146
  python -m pip install "${{ steps.build.outputs.wheel_path }}"
150
147
  python - <<'PY'
151
148
  import os
@@ -213,22 +210,35 @@ jobs:
213
210
  ${{ steps.build.outputs.wheel_path }}
214
211
  ${{ steps.build.outputs.source_distribution_path }}
215
212
 
213
+ github-release:
214
+ name: Publish GitHub release assets
215
+ needs: [validate, wheel]
216
+ runs-on: ubuntu-24.04
217
+
218
+ steps:
219
+ - name: Download release assets
220
+ uses: actions/download-artifact@v7
221
+ with:
222
+ name: src-py-lib-release
223
+ path: release-assets
224
+
216
225
  - name: Publish GitHub release assets
217
226
  env:
218
227
  GH_TOKEN: ${{ github.token }}
228
+ GH_REPO: ${{ github.repository }}
219
229
  run: |
220
- release_tag="${{ steps.release.outputs.tag }}"
221
- wheel_path="${{ steps.build.outputs.wheel_path }}"
222
- source_distribution_path="${{ steps.build.outputs.source_distribution_path }}"
223
- wheel_checksum_path="${{ steps.build.outputs.wheel_checksum_path }}"
224
- source_distribution_checksum_path="${{ steps.build.outputs.source_distribution_checksum_path }}"
225
- notes_path="${{ steps.notes.outputs.path }}"
226
- release_assets=(
227
- "${wheel_path}"
228
- "${source_distribution_path}"
229
- "${wheel_checksum_path}"
230
- "${source_distribution_checksum_path}"
231
- )
230
+ release_tag="${{ github.event.inputs.tag || github.ref_name }}"
231
+ notes_path="$(find release-assets -name release-notes.md -print -quit)"
232
+ mapfile -t release_assets < <(find release-assets -type f ! -name release-notes.md | sort)
233
+
234
+ if [[ -z "${notes_path}" ]]; then
235
+ echo "::error title=Missing release notes::release-notes.md was not found in release artifact."
236
+ exit 1
237
+ fi
238
+ if [[ "${#release_assets[@]}" -eq 0 ]]; then
239
+ echo "::error title=Missing release assets::No release assets were downloaded."
240
+ exit 1
241
+ fi
232
242
 
233
243
  if gh release view "${release_tag}" >/dev/null 2>&1; then
234
244
  gh release edit "${release_tag}" --title "${release_tag}" --notes-file "${notes_path}"
@@ -243,7 +253,7 @@ jobs:
243
253
 
244
254
  pypi:
245
255
  name: Publish PyPI package
246
- needs: wheel
256
+ needs: [validate, wheel]
247
257
  runs-on: ubuntu-24.04
248
258
  permissions:
249
259
  contents: read
@@ -0,0 +1,280 @@
1
+ name: Validate
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ ref:
7
+ description: "Git ref to validate. Defaults to the caller's ref."
8
+ required: false
9
+ type: string
10
+ build-package:
11
+ description: "Build and smoke-test package artifacts. Release builds do this separately."
12
+ required: false
13
+ type: boolean
14
+ default: true
15
+
16
+ permissions:
17
+ contents: read
18
+ pull-requests: read
19
+
20
+ defaults:
21
+ run:
22
+ shell: bash
23
+
24
+ jobs:
25
+ changes:
26
+ name: Detect changed paths
27
+ runs-on: ubuntu-24.04
28
+ outputs:
29
+ github_actions: ${{ steps.changed_paths.outputs.github_actions }}
30
+ markdown: ${{ steps.changed_paths.outputs.markdown }}
31
+ python: ${{ steps.changed_paths.outputs.python }}
32
+ package: ${{ steps.changed_paths.outputs.package }}
33
+
34
+ steps:
35
+ - name: Detect changed paths
36
+ id: changed_paths
37
+ env:
38
+ GH_TOKEN: ${{ github.token }}
39
+ PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
40
+ run: |
41
+ github_actions_changed=false
42
+ markdown_changed=false
43
+ python_changed=false
44
+ package_changed=false
45
+
46
+ if [[ "${{ github.event_name }}" != "pull_request" ]]; then
47
+ github_actions_changed=true
48
+ markdown_changed=true
49
+ python_changed=true
50
+ package_changed=true
51
+ else
52
+ changed_files="$(mktemp)"
53
+ gh api --paginate \
54
+ "repos/${GITHUB_REPOSITORY}/pulls/${PULL_REQUEST_NUMBER}/files" \
55
+ --jq '.[].filename' > "${changed_files}"
56
+
57
+ while IFS= read -r changed_file; do
58
+ case "${changed_file}" in
59
+ .github/workflows/*)
60
+ github_actions_changed=true
61
+ ;;
62
+ esac
63
+
64
+ case "${changed_file}" in
65
+ *.md|.markdownlint-cli2.yaml)
66
+ markdown_changed=true
67
+ ;;
68
+ esac
69
+
70
+ case "${changed_file}" in
71
+ .python-version|pyproject.toml|uv.lock|src/*|tests/*)
72
+ python_changed=true
73
+ ;;
74
+ esac
75
+
76
+ case "${changed_file}" in
77
+ .python-version|LICENSE|README.md|pyproject.toml|uv.lock|src/*)
78
+ package_changed=true
79
+ ;;
80
+ esac
81
+ done < "${changed_files}"
82
+ fi
83
+
84
+ {
85
+ echo "github_actions=${github_actions_changed}"
86
+ echo "markdown=${markdown_changed}"
87
+ echo "python=${python_changed}"
88
+ echo "package=${package_changed}"
89
+ } >> "${GITHUB_OUTPUT}"
90
+
91
+ github_actions:
92
+ name: Lint GitHub Actions
93
+ needs: changes
94
+ if: needs.changes.outputs.github_actions == 'true'
95
+ runs-on: ubuntu-24.04
96
+ env:
97
+ ACTIONLINT_VERSION: "1.7.12"
98
+
99
+ steps:
100
+ - name: Check out code
101
+ uses: actions/checkout@v6
102
+ with:
103
+ persist-credentials: false
104
+ ref: ${{ inputs.ref || github.ref }}
105
+
106
+ - name: Install actionlint
107
+ run: |
108
+ mkdir -p "${HOME}/.local/bin"
109
+ asset="actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
110
+ checksums="actionlint_${ACTIONLINT_VERSION}_checksums.txt"
111
+ base_url="https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}"
112
+
113
+ curl -fsSLO "${base_url}/${asset}"
114
+ curl -fsSLO "${base_url}/${checksums}"
115
+ grep " ${asset}$" "${checksums}" | sha256sum --check
116
+ tar -xzf "${asset}" -C "${HOME}/.local/bin" actionlint
117
+ chmod 0755 "${HOME}/.local/bin/actionlint"
118
+
119
+ - name: Lint GitHub Actions
120
+ run: |
121
+ "${HOME}/.local/bin/actionlint"
122
+
123
+ markdown:
124
+ name: Lint Markdown
125
+ needs: changes
126
+ if: needs.changes.outputs.markdown == 'true'
127
+ runs-on: ubuntu-24.04
128
+ env:
129
+ MARKDOWNLINT_CLI2_VERSION: "0.22.1"
130
+
131
+ steps:
132
+ - name: Check out code
133
+ uses: actions/checkout@v6
134
+ with:
135
+ persist-credentials: false
136
+ ref: ${{ inputs.ref || github.ref }}
137
+
138
+ - name: Cache npm
139
+ uses: actions/cache@v5
140
+ with:
141
+ path: ~/.npm
142
+ key: npm-${{ runner.os }}-markdownlint-cli2-${{ env.MARKDOWNLINT_CLI2_VERSION }}
143
+
144
+ - name: Lint Markdown
145
+ run: npx --yes "markdownlint-cli2@${MARKDOWNLINT_CLI2_VERSION}"
146
+
147
+ python:
148
+ name: Validate Python
149
+ needs: changes
150
+ if: needs.changes.outputs.python == 'true'
151
+ runs-on: ubuntu-24.04
152
+ env:
153
+ IMPORT_NAME: src_py_lib
154
+ PYTHON_VERSION: "3.11"
155
+ UV_VERSION: "0.11.7"
156
+
157
+ steps:
158
+ - name: Check out code
159
+ uses: actions/checkout@v6
160
+ with:
161
+ persist-credentials: false
162
+ ref: ${{ inputs.ref || github.ref }}
163
+
164
+ - name: Set up Python
165
+ uses: actions/setup-python@v6
166
+ with:
167
+ python-version: ${{ env.PYTHON_VERSION }}
168
+
169
+ - name: Cache uv
170
+ uses: actions/cache@v5
171
+ with:
172
+ path: ~/.cache/uv
173
+ key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
174
+ restore-keys: |
175
+ uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-
176
+
177
+ - name: Install uv
178
+ run: python -m pip install "uv==${UV_VERSION}"
179
+
180
+ - name: Validate lockfile
181
+ run: uv lock --check
182
+
183
+ - name: Lint Python
184
+ run: uv run --frozen ruff check .
185
+
186
+ - name: Check Python formatting
187
+ run: uv run --frozen ruff format --check .
188
+
189
+ - name: Type check
190
+ run: uv run --frozen pyright
191
+
192
+ - name: Run tests
193
+ run: uv run --frozen python -m unittest discover -s tests
194
+
195
+ - name: Smoke test source checkout import
196
+ run: |
197
+ uv run --frozen python - <<'PY'
198
+ import os
199
+
200
+ import src_py_lib
201
+
202
+ if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
203
+ raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
204
+ PY
205
+
206
+ package_build:
207
+ name: Build and smoke-test package
208
+ needs: changes
209
+ if: inputs.build-package && needs.changes.outputs.package == 'true'
210
+ runs-on: ubuntu-24.04
211
+ env:
212
+ IMPORT_NAME: src_py_lib
213
+ PYTHON_VERSION: "3.11"
214
+ UV_VERSION: "0.11.7"
215
+
216
+ steps:
217
+ - name: Check out code
218
+ uses: actions/checkout@v6
219
+ with:
220
+ persist-credentials: false
221
+ ref: ${{ inputs.ref || github.ref }}
222
+
223
+ - name: Set up Python
224
+ uses: actions/setup-python@v6
225
+ with:
226
+ python-version: ${{ env.PYTHON_VERSION }}
227
+
228
+ - name: Cache uv
229
+ uses: actions/cache@v5
230
+ with:
231
+ path: ~/.cache/uv
232
+ key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
233
+ restore-keys: |
234
+ uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-
235
+
236
+ - name: Install uv
237
+ run: python -m pip install "uv==${UV_VERSION}"
238
+
239
+ - name: Build wheel
240
+ run: uv build --wheel --out-dir dist --no-create-gitignore
241
+
242
+ - name: Smoke test installed wheel
243
+ run: |
244
+ python -m venv build/ci-venv
245
+ . build/ci-venv/bin/activate
246
+ python -m pip install dist/*.whl
247
+ python - <<'PY'
248
+ import os
249
+
250
+ import src_py_lib
251
+
252
+ if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
253
+ raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
254
+ PY
255
+
256
+ package:
257
+ name: Validate package
258
+ needs: [changes, github_actions, markdown, python, package_build]
259
+ if: always()
260
+ runs-on: ubuntu-24.04
261
+
262
+ steps:
263
+ - name: Confirm validation results
264
+ run: |
265
+ for validation_result in \
266
+ "${{ needs.changes.result }}" \
267
+ "${{ needs.github_actions.result }}" \
268
+ "${{ needs.markdown.result }}" \
269
+ "${{ needs.python.result }}" \
270
+ "${{ needs.package_build.result }}"
271
+ do
272
+ case "${validation_result}" in
273
+ success|skipped)
274
+ ;;
275
+ *)
276
+ echo "::error title=Validation failed::At least one validation job ended with '${validation_result}'."
277
+ exit 1
278
+ ;;
279
+ esac
280
+ done
@@ -64,7 +64,7 @@ uv run python -m unittest discover -s tests
64
64
  ```sh
65
65
  set -euo pipefail
66
66
 
67
- VERSION=0.1.2
67
+ VERSION=0.1.4
68
68
  BRANCH="release-v${VERSION}"
69
69
 
70
70
  git fetch origin --tags --prune
@@ -116,7 +116,7 @@ rm -rf /tmp/src-py-lib-release-check
116
116
  ```sh
117
117
  set -euo pipefail
118
118
 
119
- VERSION=0.1.2
119
+ VERSION=0.1.4
120
120
  BRANCH="release-v${VERSION}"
121
121
  GH_REPO="sourcegraph/src-py-lib"
122
122
 
@@ -140,7 +140,7 @@ gh pr merge "${BRANCH}" --repo "${GH_REPO}" --squash --delete-branch
140
140
  ```sh
141
141
  set -euo pipefail
142
142
 
143
- VERSION=0.1.2
143
+ VERSION=0.1.4
144
144
 
145
145
  git fetch origin --tags --prune
146
146
  git switch main
@@ -154,7 +154,7 @@ git push origin "v${VERSION}"
154
154
  ```sh
155
155
  set -euo pipefail
156
156
 
157
- VERSION=0.1.2
157
+ VERSION=0.1.4
158
158
  GH_REPO="sourcegraph/src-py-lib"
159
159
 
160
160
  RUN_ID="$(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: src-py-lib
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Reusable libraries for Sourcegraph projects
5
5
  Project-URL: Homepage, https://github.com/sourcegraph/src-py-lib
6
6
  Project-URL: Issues, https://github.com/sourcegraph/src-py-lib/issues
@@ -10,7 +10,7 @@ dev = [
10
10
 
11
11
  [project]
12
12
  name = "src-py-lib"
13
- version = "0.1.2"
13
+ version = "0.1.4"
14
14
  description = "Reusable libraries for Sourcegraph projects"
15
15
  readme = "README.md"
16
16
  requires-python = ">=3.11"
@@ -176,6 +176,7 @@ __all__ = [
176
176
  "load_json_cache",
177
177
  "load_json_subset",
178
178
  "logging",
179
+ "logging_context",
179
180
  "logging_settings_from_config",
180
181
  "log",
181
182
  "log_context",
@@ -8,6 +8,7 @@ import json
8
8
  import queue
9
9
  import time
10
10
  from collections.abc import Iterable, Iterator, Mapping, Sequence
11
+ from concurrent.futures import ThreadPoolExecutor, as_completed
11
12
  from dataclasses import dataclass, field
12
13
  from typing import Final, cast
13
14
  from urllib.parse import urlsplit
@@ -19,6 +20,7 @@ from src_py_lib.utils.json_types import JSONDict, JSONValue, json_dict, json_lis
19
20
  from src_py_lib.utils.logging import (
20
21
  current_trace_context,
21
22
  new_trace_context,
23
+ submit_with_log_context,
22
24
  trace_context_from_traceparent,
23
25
  traceparent_header,
24
26
  )
@@ -244,13 +246,27 @@ class SourcegraphClient:
244
246
  traces: Iterable[SourcegraphTrace] | None = None,
245
247
  *,
246
248
  retry_delays_seconds: Sequence[float] = JAEGER_TRACE_RETRY_DELAYS_SECONDS,
249
+ parallelism: int = 8,
247
250
  ) -> Iterator[SourcegraphJaegerTraceSummary]:
248
251
  """Yield compact Jaeger/debug summaries for traced Sourcegraph requests."""
249
- for trace in self.drain_traces() if traces is None else traces:
250
- yield self.fetch_jaeger_trace_summary(
251
- trace,
252
- retry_delays_seconds=retry_delays_seconds,
253
- )
252
+ if parallelism < 1:
253
+ raise ValueError("parallelism must be at least 1")
254
+ pending_traces = list(self.drain_traces() if traces is None else traces)
255
+ with ThreadPoolExecutor(
256
+ max_workers=parallelism,
257
+ thread_name_prefix="SourcegraphJaegerTrace",
258
+ ) as executor:
259
+ futures = [
260
+ submit_with_log_context(
261
+ executor,
262
+ self.fetch_jaeger_trace_summary,
263
+ trace,
264
+ retry_delays_seconds=retry_delays_seconds,
265
+ )
266
+ for trace in pending_traces
267
+ ]
268
+ for future in as_completed(futures):
269
+ yield future.result()
254
270
 
255
271
  def fetch_jaeger_trace_summary(
256
272
  self,
@@ -8,6 +8,7 @@ import json
8
8
  import logging
9
9
  import subprocess
10
10
  import tempfile
11
+ import threading
11
12
  import unittest
12
13
  from collections.abc import Mapping
13
14
  from contextlib import redirect_stderr, redirect_stdout
@@ -36,6 +37,7 @@ from src_py_lib.clients.slack import SlackClient
36
37
  from src_py_lib.clients.sourcegraph import (
37
38
  SourcegraphClient,
38
39
  SourcegraphClientConfig,
40
+ SourcegraphTrace,
39
41
  decode_external_service_id,
40
42
  decode_repository_id,
41
43
  encode_repository_id,
@@ -1535,6 +1537,50 @@ class ClientTest(unittest.TestCase):
1535
1537
  self.assertEqual(summaries[0].graphql_operations[0]["operation"], "Viewer")
1536
1538
  self.assertEqual(summaries[0].errored_spans[0]["description"], "boom")
1537
1539
 
1540
+ def test_sourcegraph_streams_jaeger_summaries_in_parallel(self) -> None:
1541
+ trace_ids = ("1" * 32, "2" * 32, "3" * 32)
1542
+ requested_trace_ids: list[str] = []
1543
+ first_batch_barrier = threading.Barrier(2, timeout=1)
1544
+
1545
+ def handler(request: httpx.Request) -> httpx.Response:
1546
+ trace_id = request.url.path.rsplit("/", 1)[-1]
1547
+ requested_trace_ids.append(trace_id)
1548
+ if trace_id in trace_ids[:2]:
1549
+ first_batch_barrier.wait()
1550
+ return httpx.Response(
1551
+ 200,
1552
+ json={
1553
+ "data": [
1554
+ {
1555
+ "spans": [
1556
+ {
1557
+ "operationName": f"trace {trace_id[0]}",
1558
+ "duration": 1_000,
1559
+ "tags": [],
1560
+ }
1561
+ ]
1562
+ }
1563
+ ]
1564
+ },
1565
+ )
1566
+
1567
+ client = SourcegraphClient(
1568
+ "https://sourcegraph.example.com/",
1569
+ "token",
1570
+ http=HTTPClient(max_attempts=1, transport=httpx.MockTransport(handler)),
1571
+ )
1572
+
1573
+ summaries = list(
1574
+ client.stream_jaeger_trace_summaries(
1575
+ [SourcegraphTrace(trace_id) for trace_id in trace_ids],
1576
+ retry_delays_seconds=(0,),
1577
+ parallelism=2,
1578
+ )
1579
+ )
1580
+
1581
+ self.assertCountEqual(requested_trace_ids, trace_ids)
1582
+ self.assertCountEqual([summary.trace.trace_id for summary in summaries], trace_ids)
1583
+
1538
1584
  def test_graphql_client_paginates_cursor_results(self) -> None:
1539
1585
  http = RecordingHTTP(
1540
1586
  [
@@ -254,7 +254,7 @@ wheels = [
254
254
 
255
255
  [[package]]
256
256
  name = "src-py-lib"
257
- version = "0.1.2"
257
+ version = "0.1.4"
258
258
  source = { editable = "." }
259
259
  dependencies = [
260
260
  { name = "httpx" },
@@ -1,124 +0,0 @@
1
- name: Validate
2
-
3
- on:
4
- workflow_call:
5
- inputs:
6
- ref:
7
- description: "Git ref to validate. Defaults to the caller's ref."
8
- required: false
9
- type: string
10
-
11
- permissions:
12
- contents: read
13
-
14
- defaults:
15
- run:
16
- shell: bash
17
-
18
- jobs:
19
- package:
20
- name: Validate package
21
- runs-on: ubuntu-24.04
22
- env:
23
- ACTIONLINT_VERSION: "1.7.12"
24
- IMPORT_NAME: src_py_lib
25
- MARKDOWNLINT_CLI2_VERSION: "0.22.1"
26
- PYTHON_VERSION: "3.11"
27
- UV_VERSION: "0.11.7"
28
-
29
- steps:
30
- - name: Check out code
31
- uses: actions/checkout@v6
32
- with:
33
- persist-credentials: false
34
- ref: ${{ inputs.ref || github.ref }}
35
-
36
- - name: Cache actionlint
37
- id: cache-actionlint
38
- uses: actions/cache@v4
39
- with:
40
- path: ~/.local/bin/actionlint
41
- key: actionlint-${{ runner.os }}-${{ runner.arch }}-${{ env.ACTIONLINT_VERSION }}
42
-
43
- - name: Install actionlint
44
- if: steps.cache-actionlint.outputs.cache-hit != 'true'
45
- run: |
46
- mkdir -p "${HOME}/.local/bin"
47
- go install "github.com/rhysd/actionlint/cmd/actionlint@v${ACTIONLINT_VERSION}"
48
- install -m 0755 "${HOME}/go/bin/actionlint" "${HOME}/.local/bin/actionlint"
49
-
50
- - name: Lint GitHub Actions
51
- run: |
52
- "${HOME}/.local/bin/actionlint"
53
-
54
- - name: Cache npm
55
- uses: actions/cache@v4
56
- with:
57
- path: ~/.npm
58
- key: npm-${{ runner.os }}-markdownlint-cli2-${{ env.MARKDOWNLINT_CLI2_VERSION }}
59
-
60
- - name: Lint Markdown
61
- run: npx --yes "markdownlint-cli2@${MARKDOWNLINT_CLI2_VERSION}"
62
-
63
- - name: Set up Python
64
- uses: actions/setup-python@v6
65
- with:
66
- python-version: ${{ env.PYTHON_VERSION }}
67
- cache: pip
68
-
69
- - name: Cache uv
70
- uses: actions/cache@v4
71
- with:
72
- path: ~/.cache/uv
73
- key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }}
74
- restore-keys: |
75
- uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-
76
-
77
- - name: Install uv
78
- run: |
79
- python -m pip install --upgrade pip
80
- python -m pip install "uv==${UV_VERSION}"
81
-
82
- - name: Validate lockfile
83
- run: uv lock --check
84
-
85
- - name: Lint Python
86
- run: uv run --frozen ruff check .
87
-
88
- - name: Check Python formatting
89
- run: uv run --frozen ruff format --check .
90
-
91
- - name: Type check
92
- run: uv run --frozen pyright
93
-
94
- - name: Run tests
95
- run: uv run --frozen python -m unittest discover -s tests
96
-
97
- - name: Smoke test source checkout import
98
- run: |
99
- uv run --frozen python - <<'PY'
100
- import os
101
-
102
- import src_py_lib
103
-
104
- if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
105
- raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
106
- PY
107
-
108
- - name: Build wheel
109
- run: uv build --wheel --out-dir dist --no-create-gitignore
110
-
111
- - name: Smoke test installed wheel
112
- run: |
113
- python -m venv build/ci-venv
114
- . build/ci-venv/bin/activate
115
- python -m pip install --upgrade pip
116
- python -m pip install dist/*.whl
117
- python - <<'PY'
118
- import os
119
-
120
- import src_py_lib
121
-
122
- if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
123
- raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
124
- PY
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes