src-py-lib 0.1.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 (33) hide show
  1. src_py_lib-0.1.1/.github/workflows/ci.yml +93 -0
  2. src_py_lib-0.1.1/.github/workflows/release.yml +235 -0
  3. src_py_lib-0.1.1/.gitignore +20 -0
  4. src_py_lib-0.1.1/.markdownlint-cli2.yaml +9 -0
  5. src_py_lib-0.1.1/.python-version +1 -0
  6. src_py_lib-0.1.1/AGENTS.md +179 -0
  7. src_py_lib-0.1.1/LICENSE +21 -0
  8. src_py_lib-0.1.1/PKG-INFO +103 -0
  9. src_py_lib-0.1.1/README.md +80 -0
  10. src_py_lib-0.1.1/SECURITY.md +3 -0
  11. src_py_lib-0.1.1/pyproject.toml +61 -0
  12. src_py_lib-0.1.1/renovate.json +14 -0
  13. src_py_lib-0.1.1/src/src_py_lib/__init__.py +170 -0
  14. src_py_lib-0.1.1/src/src_py_lib/clients/__init__.py +3 -0
  15. src_py_lib-0.1.1/src/src_py_lib/clients/github.py +157 -0
  16. src_py_lib-0.1.1/src/src_py_lib/clients/google_sheets.py +131 -0
  17. src_py_lib-0.1.1/src/src_py_lib/clients/graphql.py +476 -0
  18. src_py_lib-0.1.1/src/src_py_lib/clients/linear.py +101 -0
  19. src_py_lib-0.1.1/src/src_py_lib/clients/one_password.py +95 -0
  20. src_py_lib-0.1.1/src/src_py_lib/clients/slack.py +146 -0
  21. src_py_lib-0.1.1/src/src_py_lib/clients/sourcegraph.py +127 -0
  22. src_py_lib-0.1.1/src/src_py_lib/py.typed +0 -0
  23. src_py_lib-0.1.1/src/src_py_lib/utils/__init__.py +3 -0
  24. src_py_lib-0.1.1/src/src_py_lib/utils/config.py +603 -0
  25. src_py_lib-0.1.1/src/src_py_lib/utils/http.py +279 -0
  26. src_py_lib-0.1.1/src/src_py_lib/utils/json_cache.py +42 -0
  27. src_py_lib-0.1.1/src/src_py_lib/utils/json_types.py +54 -0
  28. src_py_lib-0.1.1/src/src_py_lib/utils/logging.py +950 -0
  29. src_py_lib-0.1.1/src/src_py_lib/utils/tsv.py +95 -0
  30. src_py_lib-0.1.1/tests/test_import.py +51 -0
  31. src_py_lib-0.1.1/tests/test_logging_http_clients.py +1981 -0
  32. src_py_lib-0.1.1/tests/test_tsv.py +65 -0
  33. src_py_lib-0.1.1/uv.lock +303 -0
@@ -0,0 +1,93 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ defaults:
13
+ run:
14
+ shell: bash
15
+
16
+ jobs:
17
+ test:
18
+ name: Build and test
19
+ runs-on: ubuntu-24.04
20
+ env:
21
+ IMPORT_NAME: src_py_lib
22
+ PYTHON_VERSION: "3.11"
23
+ UV_VERSION: "0.11.7"
24
+
25
+ steps:
26
+ - name: Check out code
27
+ uses: actions/checkout@v6
28
+ with:
29
+ persist-credentials: false
30
+
31
+ - name: Set up Python
32
+ uses: actions/setup-python@v6
33
+ with:
34
+ python-version: ${{ env.PYTHON_VERSION }}
35
+ cache: pip
36
+
37
+ - name: Install uv
38
+ run: |
39
+ python -m pip install --upgrade pip
40
+ python -m pip install "uv==${UV_VERSION}"
41
+
42
+ - name: Validate lockfile
43
+ run: uv lock --check
44
+
45
+ - name: Lint Markdown
46
+ run: npx --yes markdownlint-cli2
47
+
48
+ - name: Lint Python
49
+ run: uv run --frozen ruff check .
50
+
51
+ - name: Check Python formatting
52
+ run: uv run --frozen ruff format --check .
53
+
54
+ - name: Type check
55
+ run: uv run --frozen pyright
56
+
57
+ - name: Run tests
58
+ run: uv run --frozen python -m unittest discover -s tests
59
+
60
+ - name: Smoke test source checkout import
61
+ run: |
62
+ uv run --frozen python - <<'PY'
63
+ import os
64
+
65
+ import src_py_lib
66
+
67
+ if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
68
+ raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
69
+ PY
70
+
71
+ - name: Build wheel
72
+ run: uv build --wheel --out-dir dist --no-create-gitignore
73
+
74
+ - name: Smoke test installed wheel
75
+ run: |
76
+ python -m venv build/ci-venv
77
+ . build/ci-venv/bin/activate
78
+ python -m pip install --upgrade pip
79
+ python -m pip install dist/*.whl
80
+ python - <<'PY'
81
+ import os
82
+
83
+ import src_py_lib
84
+
85
+ if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
86
+ raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
87
+ PY
88
+
89
+ - name: Upload wheel artifact
90
+ uses: actions/upload-artifact@v7
91
+ with:
92
+ name: src-py-lib-wheel
93
+ path: dist/*.whl
@@ -0,0 +1,235 @@
1
+ name: Build release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: "Existing release tag to publish, for example v0.1.0"
11
+ required: true
12
+ type: string
13
+
14
+ permissions:
15
+ contents: write
16
+
17
+ concurrency:
18
+ group: release-${{ github.event.inputs.tag || github.ref_name }}
19
+ cancel-in-progress: false
20
+
21
+ defaults:
22
+ run:
23
+ shell: bash
24
+
25
+ jobs:
26
+ wheel:
27
+ name: Build wheel
28
+ runs-on: ubuntu-24.04
29
+ env:
30
+ IMPORT_NAME: src_py_lib
31
+ PYTHON_VERSION: "3.11"
32
+ UV_VERSION: "0.11.7"
33
+
34
+ steps:
35
+ - name: Check out release ref
36
+ uses: actions/checkout@v6
37
+ with:
38
+ fetch-depth: 0
39
+ persist-credentials: false
40
+ ref: ${{ github.event.inputs.tag || github.ref }}
41
+
42
+ - name: Set up Python
43
+ uses: actions/setup-python@v6
44
+ with:
45
+ python-version: ${{ env.PYTHON_VERSION }}
46
+ cache: pip
47
+
48
+ - name: Install build tools
49
+ run: |
50
+ python -m pip install --upgrade pip
51
+ python -m pip install "uv==${UV_VERSION}"
52
+
53
+ - name: Validate release inputs
54
+ id: release
55
+ run: |
56
+ release_tag="${{ github.event.inputs.tag || github.ref_name }}"
57
+ if [[ ! "${release_tag}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
58
+ echo "::error title=Invalid release tag::Use a vMAJOR.MINOR.PATCH tag, got '${release_tag}'."
59
+ exit 1
60
+ fi
61
+ if ! git rev-parse --verify --quiet "refs/tags/${release_tag}" >/dev/null; then
62
+ echo "::error title=Missing tag::Tag '${release_tag}' was not fetched. Create and push it before running this workflow."
63
+ exit 1
64
+ fi
65
+
66
+ project_version=$(uv run --frozen python - <<'PY'
67
+ import tomllib
68
+
69
+ with open("pyproject.toml", "rb") as pyproject_file:
70
+ print(tomllib.load(pyproject_file)["project"]["version"])
71
+ PY
72
+ )
73
+ if [[ "v${project_version}" != "${release_tag}" ]]; then
74
+ echo "::error title=Version mismatch::pyproject.toml version '${project_version}' does not match tag '${release_tag}'."
75
+ exit 1
76
+ fi
77
+
78
+ echo "tag=${release_tag}" >> "${GITHUB_OUTPUT}"
79
+
80
+ - name: Validate package
81
+ run: |
82
+ uv lock --check
83
+ uv run --frozen ruff check .
84
+ uv run --frozen ruff format --check .
85
+ uv run --frozen pyright
86
+ uv run --frozen python -m unittest discover -s tests
87
+ uv run --frozen python - <<'PY'
88
+ import os
89
+
90
+ import src_py_lib
91
+
92
+ if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
93
+ raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
94
+ PY
95
+
96
+ - name: Build distributions
97
+ id: build
98
+ run: |
99
+ dist_dir="build/release/dist"
100
+ rm -rf build/release
101
+ mkdir -p "${dist_dir}"
102
+ shopt -s nullglob
103
+
104
+ uv build --wheel --sdist --out-dir "${dist_dir}" --no-create-gitignore
105
+ project_wheels=("${dist_dir}"/*.whl)
106
+ if [[ "${#project_wheels[@]}" -ne 1 ]]; then
107
+ echo "::error title=Unexpected wheel count::Expected one project wheel, found ${#project_wheels[@]}."
108
+ exit 1
109
+ fi
110
+ source_distributions=("${dist_dir}"/*.tar.gz)
111
+ if [[ "${#source_distributions[@]}" -ne 1 ]]; then
112
+ echo "::error title=Unexpected source distribution count::Expected one source distribution, found ${#source_distributions[@]}."
113
+ exit 1
114
+ fi
115
+ wheel_path="${project_wheels[0]}"
116
+ wheel_name="$(basename "${wheel_path}")"
117
+ source_distribution_path="${source_distributions[0]}"
118
+ checksum_path="${wheel_path}.sha256"
119
+
120
+ (
121
+ cd "$(dirname "${wheel_path}")"
122
+ shasum -a 256 "${wheel_name}" > "$(basename "${checksum_path}")"
123
+ )
124
+
125
+ echo "wheel_path=${wheel_path}" >> "${GITHUB_OUTPUT}"
126
+ echo "wheel_name=${wheel_name}" >> "${GITHUB_OUTPUT}"
127
+ echo "source_distribution_path=${source_distribution_path}" >> "${GITHUB_OUTPUT}"
128
+ echo "checksum_path=${checksum_path}" >> "${GITHUB_OUTPUT}"
129
+
130
+ - name: Smoke test installed wheel
131
+ run: |
132
+ python -m venv build/release/install-venv
133
+ . build/release/install-venv/bin/activate
134
+ python -m pip install --upgrade pip
135
+ python -m pip install "${{ steps.build.outputs.wheel_path }}"
136
+ python - <<'PY'
137
+ import os
138
+
139
+ import src_py_lib
140
+
141
+ if src_py_lib.__name__ != os.environ["IMPORT_NAME"]:
142
+ raise SystemExit(f"unexpected import name: {src_py_lib.__name__}")
143
+ PY
144
+
145
+ - name: Write release notes
146
+ id: notes
147
+ run: |
148
+ release_tag="${{ steps.release.outputs.tag }}"
149
+ wheel_name="${{ steps.build.outputs.wheel_name }}"
150
+ notes_path="build/release/release-notes.md"
151
+ cat > "${notes_path}" <<EOF
152
+ ## Install
153
+
154
+ Install from PyPI:
155
+
156
+ \`\`\`sh
157
+ pip install src-py-lib
158
+ \`\`\`
159
+
160
+ Install from the release wheel:
161
+
162
+ \`\`\`sh
163
+ pip install "https://github.com/sourcegraph/src-py-lib/releases/download/${release_tag}/${wheel_name}"
164
+ \`\`\`
165
+
166
+ Or install this tag with uv:
167
+
168
+ \`\`\`sh
169
+ uv add "git+https://github.com/sourcegraph/src-py-lib.git@${release_tag}"
170
+ \`\`\`
171
+
172
+ Verify downloaded wheel assets with the matching \`.sha256\` file.
173
+ EOF
174
+ echo "path=${notes_path}" >> "${GITHUB_OUTPUT}"
175
+
176
+ - name: Upload workflow artifact
177
+ uses: actions/upload-artifact@v7
178
+ with:
179
+ name: src-py-lib-release
180
+ path: |
181
+ ${{ steps.build.outputs.wheel_path }}
182
+ ${{ steps.build.outputs.checksum_path }}
183
+ ${{ steps.notes.outputs.path }}
184
+
185
+ - name: Upload PyPI artifact
186
+ uses: actions/upload-artifact@v7
187
+ with:
188
+ name: pypi-distributions
189
+ path: |
190
+ ${{ steps.build.outputs.wheel_path }}
191
+ ${{ steps.build.outputs.source_distribution_path }}
192
+
193
+ - name: Publish GitHub release assets
194
+ env:
195
+ GH_TOKEN: ${{ github.token }}
196
+ run: |
197
+ release_tag="${{ steps.release.outputs.tag }}"
198
+ wheel_path="${{ steps.build.outputs.wheel_path }}"
199
+ checksum_path="${{ steps.build.outputs.checksum_path }}"
200
+ notes_path="${{ steps.notes.outputs.path }}"
201
+
202
+ if gh release view "${release_tag}" >/dev/null 2>&1; then
203
+ gh release edit "${release_tag}" --title "${release_tag}" --notes-file "${notes_path}"
204
+ gh release upload "${release_tag}" "${wheel_path}" "${checksum_path}" --clobber
205
+ else
206
+ gh release create "${release_tag}" \
207
+ "${wheel_path}" \
208
+ "${checksum_path}" \
209
+ --title "${release_tag}" \
210
+ --notes-file "${notes_path}" \
211
+ --verify-tag
212
+ fi
213
+
214
+ pypi:
215
+ name: Publish PyPI package
216
+ needs: wheel
217
+ runs-on: ubuntu-24.04
218
+ permissions:
219
+ contents: read
220
+ id-token: write
221
+ environment:
222
+ name: pypi
223
+ url: https://pypi.org/project/src-py-lib/
224
+
225
+ steps:
226
+ - name: Download built distribution
227
+ uses: actions/download-artifact@v7
228
+ with:
229
+ name: pypi-distributions
230
+ path: dist
231
+
232
+ - name: Publish PyPI package
233
+ uses: pypa/gh-action-pypi-publish@release/v1
234
+ with:
235
+ packages-dir: dist
@@ -0,0 +1,20 @@
1
+ # Ignore
2
+ __pycache__
3
+ .DS_Store
4
+ .pypirc
5
+ .pyright
6
+ .pytest_cache
7
+ .ruff_cache
8
+ .venv
9
+ *.env*
10
+ *.gql
11
+ *.py[cod]
12
+ *.py[oc]
13
+ *.yaml
14
+ build/
15
+ dist/
16
+ wheels/
17
+
18
+ # Allow
19
+ !.env.example
20
+ !.markdownlint-cli2.yaml
@@ -0,0 +1,9 @@
1
+ globs:
2
+ - "**/*.md"
3
+ ignores:
4
+ - ".venv/**"
5
+ - "build/**"
6
+ - "dist/**"
7
+ config:
8
+ MD013:
9
+ line_length: 100
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,179 @@
1
+ # Agents
2
+
3
+ <!-- HUMAN-MAINTAINED - START -->
4
+
5
+ ## Project principles
6
+
7
+ - This repo is public, never write non-public information in this repo
8
+ - Keep code and docs brief, for humans to read / understand / audit quickly
9
+ - Reuse and improve existing solutions / approaches / designs / helpers / tools / patterns,
10
+ before adding new / similar ones
11
+ - Keep runtime dependencies minimal; justify new dependencies in code review
12
+ - Preserve unrelated user or agent edits in the worktree
13
+
14
+ ## Standard commands
15
+
16
+ ```sh
17
+ npx --yes markdownlint-cli2
18
+ uv sync
19
+ uv run ruff format .
20
+ uv run ruff check .
21
+ uv run pyright
22
+ uv run python -m unittest discover -s tests
23
+ ```
24
+
25
+ <!-- HUMAN-MAINTAINED - END -->
26
+
27
+ <!-- AGENT-MAINTAINED - START -->
28
+
29
+ ## Toolchain
30
+
31
+ - Use `uv` for dependency management, virtualenv creation, and command running
32
+ - Use pyright in strict mode; fix linting / typing issues instead of suppressing them
33
+ - Use ruff for formatting, import sorting, and linting
34
+
35
+ ## Runtime standards
36
+
37
+ - Configure the root logger by default (`logger_name=""`) so project modules
38
+ and shared `src_py_lib` modules are captured by the same handlers
39
+ - Startup logs should include command, sanitized runtime config, commit when
40
+ available, and log file path when applicable
41
+ - Use shared HTTP/client helpers for timeout policy, API error wrapping, and
42
+ rate-limit handling
43
+
44
+ ## Code organization
45
+
46
+ - Put importable package code under `src/`
47
+ - Put tests under `tests/`
48
+ - Keep module-level constants near the top of each module, after imports
49
+ - Prefer specific package/module names over broad `helpers` or `utils` modules
50
+
51
+ ## Release process
52
+
53
+ - The tagged source commit must already contain the package version it
54
+ releases. Do not make the release workflow edit `pyproject.toml`.
55
+ - The tag must be `vMAJOR.MINOR.PATCH`, and `.github/workflows/release.yml`
56
+ verifies that it matches `project.version` before building GitHub release
57
+ assets and publishing to PyPI.
58
+ - Prepare releases on a branch from current `main`. Set `VERSION`, then run:
59
+
60
+ ```sh
61
+ set -euo pipefail
62
+
63
+ VERSION=0.1.1
64
+ BRANCH="release-v${VERSION}"
65
+
66
+ git fetch origin --tags --prune
67
+ git switch main
68
+ git pull --ff-only
69
+ git switch -c "${BRANCH}"
70
+
71
+ uv run python - "${VERSION}" <<'PY'
72
+ from pathlib import Path
73
+ import re
74
+ import sys
75
+
76
+ version = sys.argv[1]
77
+ path = Path("pyproject.toml")
78
+ text = path.read_text()
79
+ new_text = re.sub(
80
+ r'(?m)^version = "[^"]+"$',
81
+ f'version = "{version}"',
82
+ text,
83
+ count=1,
84
+ )
85
+ if new_text == text:
86
+ raise SystemExit("pyproject.toml version was not updated")
87
+ path.write_text(new_text)
88
+ PY
89
+
90
+ uv lock
91
+ ```
92
+
93
+ - Validate before opening the PR:
94
+
95
+ ```sh
96
+ set -euo pipefail
97
+
98
+ uv lock --check
99
+ npx --yes markdownlint-cli2
100
+ uv run ruff check .
101
+ uv run ruff format --check .
102
+ uv run pyright
103
+ uv run python -m unittest discover -s tests
104
+ uv build --wheel --sdist --out-dir /tmp/src-py-lib-release-check --no-create-gitignore
105
+ rm -rf /tmp/src-py-lib-release-check
106
+ ```
107
+
108
+ - Commit, push, open the PR, wait for checks, then merge it. If review is
109
+ required, stop after `gh pr checks` and ask for review before merging.
110
+
111
+ ```sh
112
+ set -euo pipefail
113
+
114
+ VERSION=0.1.1
115
+ BRANCH="release-v${VERSION}"
116
+ GH_REPO="sourcegraph/src-py-lib"
117
+
118
+ git add pyproject.toml uv.lock
119
+ git commit -m "Release v${VERSION}"
120
+ git push -u origin "${BRANCH}"
121
+
122
+ gh pr create \
123
+ --repo "${GH_REPO}" \
124
+ --base main \
125
+ --head "${BRANCH}" \
126
+ --title "Release v${VERSION}" \
127
+ --body "Bump src-py-lib package metadata to ${VERSION}."
128
+
129
+ gh pr checks "${BRANCH}" --repo "${GH_REPO}" --watch --fail-fast
130
+ gh pr merge "${BRANCH}" --repo "${GH_REPO}" --squash --delete-branch
131
+ ```
132
+
133
+ - Tag the merged `main` commit. Do not tag a branch commit.
134
+
135
+ ```sh
136
+ set -euo pipefail
137
+
138
+ VERSION=0.1.1
139
+
140
+ git fetch origin --tags --prune
141
+ git switch main
142
+ git pull --ff-only
143
+ git tag "v${VERSION}"
144
+ git push origin "v${VERSION}"
145
+ ```
146
+
147
+ - Watch the release workflow and confirm the GitHub release and PyPI project.
148
+
149
+ ```sh
150
+ set -euo pipefail
151
+
152
+ VERSION=0.1.1
153
+ GH_REPO="sourcegraph/src-py-lib"
154
+
155
+ RUN_ID="$(
156
+ gh run list \
157
+ --repo "${GH_REPO}" \
158
+ --workflow release.yml \
159
+ --branch "v${VERSION}" \
160
+ --limit 1 \
161
+ --json databaseId \
162
+ --jq '.[0].databaseId // empty'
163
+ )"
164
+ test -n "${RUN_ID}"
165
+ gh run watch "${RUN_ID}" --repo "${GH_REPO}" --exit-status
166
+ gh release view "v${VERSION}" --repo "${GH_REPO}"
167
+ uvx --from pip pip index versions src-py-lib
168
+ ```
169
+
170
+ - If a pushed tag points at the wrong commit, move it only after explicit
171
+ human approval.
172
+
173
+ ## Before finishing changes
174
+
175
+ - Re-read edited files for organization and stale comments
176
+ - Update `README.md` when setup or user-facing behavior changes
177
+ - Update this `AGENTS.md` only with durable project-specific discoveries
178
+
179
+ <!-- AGENT-MAINTAINED - END -->
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sourcegraph
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: src-py-lib
3
+ Version: 0.1.1
4
+ Summary: Reusable libraries for Sourcegraph projects
5
+ Project-URL: Homepage, https://github.com/sourcegraph/src-py-lib
6
+ Project-URL: Issues, https://github.com/sourcegraph/src-py-lib/issues
7
+ Author: Sourcegraph
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: Sourcegraph
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: httpx<1,>=0.28
20
+ Requires-Dist: pydantic<3,>=2
21
+ Requires-Dist: python-dotenv<2,>=1.2
22
+ Description-Content-Type: text/markdown
23
+
24
+ # src-py-lib
25
+
26
+ Reusable libraries for Sourcegraph projects
27
+
28
+ ## Experimental - This is not a supported Sourcegraph product
29
+
30
+ This repo was created for Sourcegraph Implementation Engineering deployments,
31
+ and is not intended, designed, built, or supported for use in any other scenario.
32
+ Feel free to open issues or PRs, but responses are best effort.
33
+
34
+ ## Install
35
+
36
+ From PyPI:
37
+
38
+ ```sh
39
+ uv add src-py-lib
40
+ ```
41
+
42
+ From this repository:
43
+
44
+ ```sh
45
+ uv add git+https://github.com/sourcegraph/src-py-lib.git
46
+ ```
47
+
48
+ ## Use it for
49
+
50
+ - Typed config models loaded from defaults, `.env`, environment variables, and CLI flags
51
+ - Root logger setup with terminal output, optional JSONL events, timing, and run metadata
52
+ - A shared `httpx` JSON client with timeouts, retries, `Retry-After`, and contextual errors
53
+ - Small helpers for TSV output, JSON caches, GraphQL pagination, and batched GraphQL queries
54
+ - Thin clients for Sourcegraph, Linear, Slack, GitHub, Google Sheets, and 1Password
55
+
56
+ Prefer vendor SDKs when they handle complex auth, token refresh, quota behavior,
57
+ pagination, retries, or request models better than a thin wrapper
58
+
59
+ ## Quick example
60
+
61
+ Define a project config, parse it once, and configure logging at startup:
62
+
63
+ ```python
64
+ from pathlib import Path
65
+
66
+ import src_py_lib as src
67
+
68
+
69
+ class LinearExportConfig(src.LinearClientConfig):
70
+ output_dir: Path = src.config_field(
71
+ default=Path("."),
72
+ env_var="LINEAR_EXPORT_OUTPUT_DIR",
73
+ cli_flag="--output-dir",
74
+ metavar="PATH",
75
+ help="Directory for generated files.",
76
+ )
77
+
78
+ config = src.parse_args(LinearExportConfig, description="Export Linear data")
79
+
80
+ with src.logging(config):
81
+ client = src.linear_client_from_config(config)
82
+ client.validate()
83
+ src.info("Starting export", output_dir=str(config.output_dir))
84
+ ```
85
+
86
+ - Config precedence is code defaults, `.env`, shell environment, then CLI overrides
87
+ - `parse_args` resolves `op://...` references by default
88
+ - Mark sensitive fields with `secret=True` so config snapshots redact resolved values
89
+ - `src.logging()` configures the root logger by default so project code and `src_py_lib` internals
90
+ share the same handlers
91
+ - Use `event()` for timed work, `stage()` for workflow context, and
92
+ `info()` / `warning()` / `error()` for structured one-off events
93
+
94
+ ## Development
95
+
96
+ ```sh
97
+ uv sync
98
+ uv run ruff format .
99
+ uv run ruff check .
100
+ uv run pyright
101
+ uv run python -m unittest discover -s tests
102
+ npx --yes markdownlint-cli2
103
+ ```