pystata-x
Independent drop-in replacement for StataCorp's pystata. Provides a
fast stata_setup initialiser and command execution path that delivers
~10–20,000× speedup on short commands and ~11× faster cold Stata
initialisation.
Quick Start
import sys
sys.path.insert(0, "path/to/pystata-x/src")
from pystata_x.stata_setup import config
config("/Applications/StataMP", "mp", splash=False)
# Use our fast execution:
from pystata_x._core import execute
output, rc = execute("display 1+1")
print(output) # "2"
Or use the vendor-compatible API:
from pystata_x._core import run
run("sysuse auto, clear") # prints output, raises SystemError on error
Why the polling thread is the bottleneck
The original pystata.stata.run() calls RedirectOutput from
pystata.core.stout, which creates a RepeatTimer thread that polls
Stata's output buffer every 15 ms:
- A background thread is created and started.
- Every 15 ms it calls
StataSO_getOutput()to fetch and display output. - After the command finishes a
"#return;0"sentinel appears, the thread exits and is joined.
This design exists to support Jupyter notebook interactivity — users see
output streaming in as commands execute, like a live terminal. The polling
sleep (15 ms) plus thread lifecycle overhead adds ~40 ms of Python
overhead on every run() call:
pystata.stata.run() → ~40 ms total
├─ thread create ~1 ms
├─ 3× poll cycle ~45 ms (3 × 15 ms)
├─ thread join ~1 ms
└─ work overhead ~1 ms
For headless / CLI / AI-agent use cases (e.g., stata-agent), output is
captured programmatically after the command finishes — no streaming to a
terminal or notebook is needed. The polling thread is pure overhead.
pystata-x skips the thread entirely and calls StataSO_Execute() directly,
then drains the output buffer once after execution.
Benchmark Results
Measured on macOS (StataSE, Apple Silicon M4) using
benchmarks/run_benchmarks.py. Each test runs in a fresh subprocess
(Stata initialised once per test) with warm-up iterations before timing.
Times are the mean of multiple iterations measured via
time.perf_counter().
Command execution
| Test | Original pystata | pystata-x | Speedup |
|---|---|---|---|
Single command (display 1+1) |
~40.6 ms | ~0.002 ms | ~19,000× |
| Single command + echo | ~40.7 ms | ~0.002 ms | ~17,000× |
| Single command (quietly) | ~40.4 ms | ~0.002 ms | ~20,000× |
| Multi-line (4 commands, do-file) | ~41.9 ms | ~3.2 ms | ~13× |
| Raw StataSO_Execute (no wrapper) | ~0.002 ms | ~0.002 ms | 1× (baseline) |
Cold initialisation
| Method | Time | Speedup |
|---|---|---|
Original stata_setup.config() (→ pystata) |
~1.50 s | 1× |
Optimised pystata_x._config.init() |
~0.13 s | ~11× |
Optimised pystata_x.stata_setup.config() |
~0.13 s | ~11× |
Why cold init is faster
The original pystata.config.init() does several expensive things that pystata_x's
init skips:
| Step | Original | pystata-x |
|---|---|---|
| IPython/Jupyter probe | ~100 ms (imports IPython, checks for kernel) |
Skipped |
| Preference-file I/O | ~50 ms (reads profile.ini from disk) |
Skipped |
| Python 2 compat setup | ~30 ms (try/except on every str() conversion) |
Removed |
stata_setup wrapper overhead |
~50 ms (filesystem checks, extra imports) | Inlined |
| Total | ~1.50 s | ~0.13 s |
Project Structure
src/pystata_x/
├── __init__.py # Package entry point
├── _config.py # Fast Stata initialisation (no IPython/py2 compat)
├── _core.py # Fast command execution (direct StataSO_Execute)
└── stata_setup.py # Drop-in replacement for PyPI `stata-setup`
benchmarks/
├── run_benchmarks.py # Comprehensive benchmark runner
└── history/ # Benchmark result history
Cross-platform
Shared-library discovery in _config.py supports macOS, Linux, and Windows:
| Platform | Library name | Search path |
|---|---|---|
| macOS | libstata-{be,se,mp}.dylib |
Stata{B,E,MP}E.app/Contents/MacOS/ |
| Linux | libstata-{be,se,mp}.so |
{st_path}/ |
| Windows | libstata-{be,se,mp}.dll |
{st_path}/ |
Licence
- Our modules (
_config.py,_core.py,stata_setup.py,__init__.py, and all files underbenchmarks/) are original work, released under the GNU Affero General Public License v3.0. - The PyPI
stata-setuppackage (v0.1.3, StataCorp LLC) is Apache 2.0 licenced — ourstata_setup.pyprovides the same public API with a completely rewritten implementation under AGPL-3.0.
Metadata
Release files for pystata-x 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pystata_x-0.1.2.tar.gz | 37.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pystata_x-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.6 kB
Release files / pystata_x-0.1.2.tar.gz
| Download URL | pystata_x-0.1.2.tar.gz |
|---|---|
| Size | 37.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2824355463d5baa04646d552c9d60a7fc636a3073577cb4d71d068b61bb74398
|
|
BLAKE2b-256 checksum How to use checksums |
514de84d82e9895b70709ec181376228c17f990d98d7a2d8550441bd875e4d9c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 16, 2026.
Transparency logRelease files / pystata_x-0.1.2-py3-none-any.whl
| Download URL | pystata_x-0.1.2-py3-none-any.whl |
|---|---|
| Size | 25.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
064e1997f53e377fe8b0280b17c8909eb904199aab1f39aacdc94db7d82338b0
|
|
BLAKE2b-256 checksum How to use checksums |
d26812474a047c27eed3878aa1cbed618b17011c8ffe9a3e4b0dbb785a478747
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 16, 2026.
Transparency log