Query PeachQ from Python¶
Watch Kola and qPython connect to PeachQ, followed by Kola's compatibility tests. Use the player's fullscreen control for a larger view. Curl download waits are shortened.
Send a Python DataFrame to PeachQ. Group the trades in q. Get a Polars DataFrame back, ready for your next calculation or chart.
sym volume notional
AAPL 30 3200.0
MSFT 5 1000.0
Clients¶
Both clients connect to a separate PeachQ process over q IPC.
| Client | Python data | When to use it |
|---|---|---|
| Kola | Polars DataFrames and Series | Start here for a new project. Requires Python 3.10 or newer. |
| qPython | NumPy arrays and structured arrays | Existing qPython code with older dependencies. See the restrictions below. |
These clients send queries from Python to q. Calling Python from q is a different workflow: use embedPy.
Kola¶
Use Linux x86-64, Bash, curl, tar, and Python 3.10 or newer with venv and pip.
Start in a fresh directory. The server runs in one terminal; Python connects
from another.
Terminal 1: download and start PeachQ:
mkdir peachq-python-api && cd peachq-python-api
mkdir peachq
curl -fL https://peachq.org/download/peachq-linux-x64.tar.gz | tar -xz -C peachq
./peachq/q -p 5010
Terminal 2: install Kola and run the example:
cd peachq-python-api
python3 -m venv .venv
. .venv/bin/activate
python -m pip install kola 'polars[rtcompat]'
python - <<'PY'
import polars as pl
from kola import Q
trades = pl.DataFrame({
'sym': ['AAPL', 'MSFT', 'AAPL'],
'price': [100., 200., 110.],
'size': [10, 5, 20],
}).with_columns(pl.col('sym').cast(pl.Categorical))
q = Q('127.0.0.1', 5010)
q.connect()
try:
q.sync('set', 'trade', trades)
assert q.sync('count trade') == 3
result = q.sync('0!select volume:sum size,notional:sum price*size by sym from trade')
assert result.to_dicts() == [
{'sym': 'AAPL', 'volume': 30, 'notional': 3200.},
{'sym': 'MSFT', 'volume': 5, 'notional': 1000.},
]
print(result)
finally:
q.disconnect()
PY
The result contains the two rows shown above. polars[rtcompat] also works on
CPUs and virtual machines without AVX2. If your machine supports the standard
Polars runtime, installing kola alone is sufficient.
Upload¶
pl.Categorical sends sym as q symbols. The numeric columns become float and
long vectors. Pass the DataFrame as an argument, rather than constructing q
source from its values:
q.sync('set', 'trade', trades)
set creates or replaces trade on the server. The table remains there after
the Python connection closes, until the server exits or you replace it.
To append another batch later, use the pattern from Kola's upload example:
q.sync('upsert', 'trade', trades)
For this unkeyed table, upsert appends rows. Sending the same batch again adds
duplicates; the complete example uses set so rerunning it gives the same result.
Query¶
Kola accepts q query strings and returns tables as Polars DataFrames:
result = q.sync('select from trade where size>=10')
This selects the two AAPL trades. To group the original table instead:
result = q.sync('0!select volume:sum size,notional:sum price*size by sym from trade')
sum size totals each symbol's volume. sum price*size totals its trade value.
0! turns the grouped result into an ordinary table, which Kola returns as a
Polars DataFrame. Use result.to_dicts() for Python dictionaries or continue
with Polars expressions.
For a parameterized calculation, pass a value separately:
q.sync('{sum x}', pl.Series('sizes', [10, 5, 20], dtype=pl.Int64))
# 35
Run these calls while the connection is open. Press Ctrl+C in terminal 1 when you have finished with the server.
Run Kola's tests against PeachQ¶
Run Kola compatibility tests (no Rust build required)
The suite checks q IPC reads and writes for atoms, vectors, tables and
dictionaries, plus asynchronous calls, errors and Kola's operator encoding.
Run the upstream Python tests against the installed Kola wheel with pytest,
excluding one DNS-message test that does not connect to PeachQ.
You also need Git and lsof. In terminal 2, from peachq-python-api with
.venv active, run:
python -m pip install 'kola==2.6.1' 'polars[rtcompat]' pytest
git clone https://github.com/jshinonome/kola.git kola-tests
git -C kola-tests checkout ff35ebb1b62decab0f6e036c42c59eb5494853f0
(
if lsof -i:1801 >/dev/null; then
echo 'Port 1801 is in use. Free it before running these tests.'
exit 1
fi
PATH="$PWD/peachq:$PATH" TZ=UTC python -m pytest \
--import-mode=importlib kola-tests/py-kola/test -q -k "not test_io_error"
)
The test revision matches Kola 2.6.1. --import-mode=importlib uses the
installed wheel without importing the unbuilt Python package in the clone.
The upstream fixture
starts the downloaded peachq/q on port 1801 and stops it afterwards;
the example server on port 5010 can stay running. Keep port 1801 unused:
the fixture attempts to kill a process already using that port.
TZ=UTC avoids the scalar null-date conversion issue described below.
The -k "not test_io_error" filter excludes only the test that expects
specific OS resolver wording for the hostname DUMMY. Pytest reports it
as deselected. To run the complete upstream suite, remove that filter;
a different DNS error message can fail that test without involving PeachQ.
Read pytest's final passed, failed, skipped and deselected counts. Skipped IPC tests do not demonstrate server compatibility. Passing tests cover the selected cases, not every q feature or Kola workflow.
qPython¶
The original exxeleron project is in maintenance mode. It cannot import with
NumPy 2, and requires NumPy older than 1.24 for its removed type aliases. Use a
separate Python 3.10 or 3.11 environment for this example. Here, python3
must refer to one of those versions; the pinned NumPy does not support Python
3.12 or newer:
python3 -m venv .qpython-venv
. .qpython-venv/bin/activate
python -m pip install setuptools 'numpy==1.23.5' 'qPython==2.0.0'
python - <<'PY'
import numpy as np
from qpython.qconnection import QConnection
with QConnection(host='127.0.0.1', port=5010) as q:
assert q.sendSync('1+1') == 2
total = q.sendSync('{sum x}', np.array([10, 5, 20], dtype=np.int64))
assert total == 35
print(total)
print(q.sendSync('([]sym:`AAPL`MSFT;volume:30 5;notional:3200 1000f)'))
PY
This returns NumPy data, including a structured array for the table. Keep
pandas=True off: qPython's direct pandas conversion fails with pandas 1.5.3.
Limitations¶
You can now upload a table, aggregate it in PeachQ and use the result in Python.
- Kola can raise a conversion error for the scalar null date
0Ndwhen Python uses the Europe/London timezone. Starting Python withTZ=UTCavoids this; the null becomesdatetime.date(1, 1, 1), notNone. - qPython needs the older environment above and cannot convert tables with
pandas=Trueunder pandas 1.5.3. Use its default NumPy output instead.