Skip to content

Commit 8a00c0e

Browse files
committed
release origin and test expansion
1 parent 7cd499e commit 8a00c0e

19 files changed

Lines changed: 617 additions & 451 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ENV/
1212
# stackql
1313
.stackql/
1414
stackql
15+
stackql.exe
1516
stackql-*.sh
1617
.env
1718
nohup.out

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## v3.8.3 (2026-06-29)
4+
5+
### Updates
6+
7+
- Routed all binary downloads through `releases.stackql.io` (including macOS) and added a `pystackql/{version}` User-Agent so downloads can be identified
8+
- Updated the test suite and test runners for Linux and Windows
9+
310
## v3.8.2 (2025-11-09)
411

512
### New Features

CLAUDE.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# CLAUDE.md
2+
3+
PyStackQL - a Python wrapper for the [StackQL](https://stackql.io) query engine, which runs SQL against cloud and SaaS providers. Published to PyPI as `pystackql`.
4+
5+
## Layout
6+
7+
- `pystackql/core/` - main logic
8+
- `stackql.py` - `StackQL` class, the primary public interface (`execute`, `executeStmt`, `executeQueriesAsync`, `properties`, `upgrade`, `test_connection`)
9+
- `query.py` - `QueryExecutor` / `AsyncQueryExecutor`
10+
- `server.py` - `ServerConnection` (server mode via psycopg/postgres wire protocol)
11+
- `output.py` - `OutputFormatter` (output formats: `dict`, `pandas`, `csv`, `markdownkv`)
12+
- `binary.py` - `BinaryManager` (locates/downloads the stackql binary)
13+
- `error_detector.py` - `ErrorDetector`, matches messages against patterns in `pystackql/errors.yaml`
14+
- `pystackql/utils/` - platform, binary, download, auth, and param helpers (re-exported from `utils/__init__.py`)
15+
- `pystackql/magic_ext/` - Jupyter magics: `StackqlMagic` (local) and `StackqlServerMagic` (server), sharing `base.py`
16+
- `pystackql/__init__.py` - public API: `StackQL`, `StackqlMagic`, `StackqlServerMagic`
17+
18+
## Two execution modes
19+
20+
- **Local mode** (default): downloads/runs the stackql binary as a subprocess.
21+
- **Server mode** (`server_mode=True`): connects to a running stackql server over the postgres wire protocol. `csv` output and several local-only options are unsupported here.
22+
23+
## Testing
24+
25+
Tests use the no-auth Homebrew provider and provider-agnostic literal queries (avoid adding auth-requiring tests).
26+
27+
- Non-server tests: `python run_tests.py` (optionally pass specific `tests/test_*.py` files, `-v`)
28+
- Server tests: start a server first (`stackql srv --pgsrv.address 127.0.0.1 --pgsrv.port 5466`), then `python run_server_tests.py`
29+
- CI (`.github/workflows/test.yaml`) runs both across Linux/macOS/Windows and Python 3.9-3.13.
30+
31+
## Conventions
32+
33+
- Supports Python 3.9-3.13 on Windows, macOS, and Linux - keep changes cross-platform.
34+
- `README.rst` is reStructuredText (the PyPI readme); docs in `docs/` build to ReadTheDocs from Sphinx-style docstrings. Update the `StackQL.__init__` docstring when changing constructor params.
35+
- Bump `version` in `pyproject.toml` for releases; record changes in `CHANGELOG.md`.

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,14 @@ To build the package, you will need to install the following packages:
144144

145145
::
146146

147-
pip install build
147+
pip install build twine
148148

149149
Then, from the root directory of the repository, run:
150150

151151
::
152152

153153
rm -rf dist/*
154-
python3 -m build
154+
python3 -m build
155155

156156
The package will be built in the ``dist`` directory.
157157

launch_venv.sh

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

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "pystackql"
7-
version = "3.8.2"
7+
version = "3.8.3"
88
description = "A Python interface for StackQL"
99
readme = "README.rst"
1010
authors = [

pystackql/core/stackql.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,23 @@ def __init__(self,
170170
self.server_port = server_port
171171
self.server_connection = ServerConnection(server_address, server_port)
172172
else:
173-
# Local mode - execute the binary locally
174-
# Get all parameters from local variables (excluding 'self')
175-
local_params = locals().copy()
176-
local_params.pop('self')
177-
173+
# Local mode - execute the binary locally.
174+
# Combine the explicit constructor arguments with any additional
175+
# **kwargs (e.g. download_dir, api_timeout, proxy settings, custom_auth).
176+
# kwargs is spread flat so these reach setup_local_mode as top-level
177+
# keys rather than being nested under a 'kwargs' entry.
178+
local_params = {
179+
'server_mode': server_mode,
180+
'server_address': server_address,
181+
'server_port': server_port,
182+
'output': output,
183+
'sep': sep,
184+
'header': header,
185+
'debug': debug,
186+
'debug_log_file': debug_log_file,
187+
**kwargs,
188+
}
189+
178190
# Set up local mode - this sets the instance attributes and returns params
179191
self.params = setup_local_mode(self, **local_params)
180192

pystackql/utils/download.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@
1111
import platform
1212
import requests
1313

14+
from .package import get_package_version
15+
16+
# Base URL for all stackql binary downloads. This is a Cloudflare proxy in front
17+
# of the GitHub releases, used so downloads can be attributed and cached.
18+
RELEASES_BASE_URL = 'https://releases.stackql.io/stackql/latest'
19+
20+
21+
def get_user_agent():
22+
"""Builds the User-Agent string used for stackql binary downloads.
23+
24+
The versioned identifier (e.g. ``pystackql/3.8.2``) lets the proxy logs
25+
attribute downloads to pystackql.
26+
27+
Returns:
28+
str: The User-Agent header value
29+
"""
30+
version = get_package_version("pystackql") or "unknown"
31+
return f"pystackql/{version}"
32+
1433

1534
def get_download_dir():
1635
"""Gets the directory to download the stackql binary.
@@ -38,11 +57,11 @@ def get_download_url():
3857
machine_val = platform.machine()
3958

4059
if system_val == 'Linux' and machine_val == 'x86_64':
41-
return 'https://releases.stackql.io/stackql/latest/stackql_linux_amd64.zip'
60+
return f'{RELEASES_BASE_URL}/stackql_linux_amd64.zip'
4261
elif system_val == 'Windows':
43-
return 'https://releases.stackql.io/stackql/latest/stackql_windows_amd64.zip'
62+
return f'{RELEASES_BASE_URL}/stackql_windows_amd64.zip'
4463
elif system_val == 'Darwin':
45-
return 'https://storage.googleapis.com/stackql-public-releases/latest/stackql_darwin_multiarch.pkg'
64+
return f'{RELEASES_BASE_URL}/stackql_darwin_multiarch.pkg'
4665
else:
4766
raise Exception(f"ERROR: [get_download_url] unsupported OS type: {system_val} {machine_val}")
4867

@@ -59,7 +78,8 @@ def download_file(url, path, showprogress=True):
5978
Exception: If the download fails
6079
"""
6180
try:
62-
r = requests.get(url, stream=True)
81+
headers = {"User-Agent": get_user_agent()}
82+
r = requests.get(url, stream=True, headers=headers)
6383
r.raise_for_status()
6484
total_size_in_bytes = int(r.headers.get('content-length', 0))
6585
block_size = 1024

0 commit comments

Comments
 (0)