Skip to content

Commit c18a946

Browse files
authored
Automate PyPI release pipeline and modernize packaging (#26)
* Migrate packaging metadata to pyproject.toml (PEP 621) Replace setup.py and Pipenv files with a complete PEP 621 pyproject.toml: - Full [project] table with metadata, classifiers, optional-deps - Dynamic version via setuptools AST parsing of serpapi/__version__.py - pytest configuration in [tool.pytest.ini_options] - Remove setup.py, Pipfile, and Pipfile.lock * Update CI workflow: clean up steps, gate example tests to Python 3.13 * Add automated PyPI release workflow Tag-triggered (v*) pipeline: - test: run unit tests across Python 3.6–3.13, example tests on 3.13 only - build: produce sdist and wheel via python -m build - publish: create GitHub Release and upload to PyPI via twine - smoke-test: install from PyPI and verify version + live search * Ignore local .venv/ directory * Document release process in README
1 parent 6493de6 commit c18a946

File tree

8 files changed

+221
-773
lines changed

8 files changed

+221
-773
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,24 @@ jobs:
1919

2020
steps:
2121
- name: Checkout repository
22-
uses: actions/checkout@v4
22+
uses: actions/checkout@v6
2323

2424
- name: Set up Python ${{ matrix.python-version }}
25-
uses: actions/setup-python@v5
25+
uses: actions/setup-python@v6
2626
with:
2727
python-version: ${{ matrix.python-version }}
2828

2929

3030
- name: Install dependencies
3131
run: pip install -e .[test]
3232

33-
- name: Test with pytest
34-
run: |
35-
if [ "${{ matrix.python-version }}" == "3.11" ]; then
36-
pytest
37-
else
38-
pytest -k "not example"
39-
fi
33+
- name: Run tests
34+
run: pytest -k "not example"
4035
env:
41-
API_KEY: ${{secrets.API_KEY}}
36+
API_KEY: ${{ secrets.API_KEY }}
37+
38+
- name: Run example tests
39+
if: matrix.python-version == '3.13'
40+
run: pytest -k "example"
41+
env:
42+
API_KEY: ${{ secrets.API_KEY }}

.github/workflows/release.yml

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags: ['v**']
6+
7+
concurrency:
8+
group: ${{ github.workflow }}-${{ github.ref }}
9+
cancel-in-progress: false
10+
11+
jobs:
12+
test:
13+
name: Test / Python ${{ matrix.python-version }}
14+
runs-on: ubuntu-latest
15+
strategy:
16+
matrix:
17+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
18+
steps:
19+
- uses: actions/checkout@v6
20+
21+
- uses: actions/setup-python@v6
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
25+
- name: Install dependencies
26+
run: pip install -e .[test]
27+
28+
- name: Run tests
29+
run: pytest -k "not example"
30+
env:
31+
API_KEY: ${{ secrets.API_KEY }}
32+
33+
- name: Run example tests
34+
if: matrix.python-version == '3.13'
35+
run: pytest -k "example"
36+
env:
37+
API_KEY: ${{ secrets.API_KEY }}
38+
39+
build:
40+
name: Build distribution
41+
needs: [test]
42+
runs-on: ubuntu-latest
43+
steps:
44+
- uses: actions/checkout@v6
45+
46+
- uses: actions/setup-python@v6
47+
with:
48+
python-version: "3.13"
49+
50+
- name: Build sdist and wheel
51+
run: |
52+
pip install build
53+
python -m build
54+
55+
- uses: actions/upload-artifact@v7
56+
with:
57+
name: dist
58+
path: dist/
59+
if-no-files-found: error
60+
61+
publish:
62+
name: Publish release
63+
needs: [build]
64+
runs-on: ubuntu-latest
65+
permissions:
66+
contents: write
67+
packages: write
68+
steps:
69+
- uses: actions/download-artifact@v8
70+
with:
71+
name: dist
72+
path: dist/
73+
74+
- uses: actions/setup-python@v6
75+
with:
76+
python-version: "3.13"
77+
78+
- name: Create GitHub Release
79+
env:
80+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
81+
GH_REPO: ${{ github.repository }}
82+
run: |
83+
gh release create ${{ github.ref_name }} dist/* --generate-notes \
84+
|| gh release upload ${{ github.ref_name }} dist/* --clobber
85+
86+
- name: Install twine
87+
run: pip install --upgrade pip twine
88+
89+
- name: Publish to PyPI
90+
env:
91+
TWINE_USERNAME: __token__
92+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
93+
run: twine upload dist/*
94+
95+
- name: Publish to GitHub Packages
96+
env:
97+
TWINE_USERNAME: ${{ github.repository_owner }}
98+
TWINE_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
99+
run: twine upload --repository-url https://upload.pypi.pkg.github.com/${{ github.repository_owner }}/ dist/*
100+
101+
smoke-test:
102+
name: Smoke test published package
103+
needs: [publish]
104+
runs-on: ubuntu-latest
105+
steps:
106+
- uses: actions/setup-python@v6
107+
with:
108+
python-version: "3.13"
109+
110+
- name: Wait for PyPI availability
111+
run: |
112+
VERSION=${GITHUB_REF_NAME#v}
113+
echo "Waiting for serpapi==$VERSION on PyPI..."
114+
for i in $(seq 1 12); do
115+
if pip index versions serpapi 2>/dev/null | grep -q "$VERSION"; then
116+
echo "Available!"
117+
exit 0
118+
fi
119+
echo "Attempt $i/12 — sleeping 10s..."
120+
sleep 10
121+
done
122+
echo "Timed out waiting for PyPI propagation" && exit 1
123+
124+
- name: Install from PyPI
125+
run: |
126+
VERSION=${GITHUB_REF_NAME#v}
127+
pip install "serpapi==$VERSION"
128+
129+
- name: Verify import and version
130+
env:
131+
API_KEY: ${{ secrets.API_KEY }}
132+
run: |
133+
VERSION=${GITHUB_REF_NAME#v}
134+
python - <<PY
135+
import os
136+
import serpapi
137+
assert serpapi.__version__ == '$VERSION', f'Version mismatch: {serpapi.__version__} != $VERSION'
138+
print(f'OK: serpapi=={serpapi.__version__} installed successfully')
139+
client = serpapi.Client(api_key=os.environ["API_KEY"])
140+
results = client.search({"engine": "google", "q": "coffee"})
141+
assert results.get("organic_results"), "No organic results returned"
142+
print(f'OK: live search returned {len(results["organic_results"])} organic results')
143+
PY

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ __pycache__
1616

1717
.vscode
1818
t.py
19+
.venv/

Pipfile

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)