stata-cli 0.2.0__py3-none-any.whl

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.
stata_cli/utils.py ADDED
@@ -0,0 +1,85 @@
1
+ """Platform detection and Stata path auto-discovery."""
2
+
3
+ import os
4
+ import platform
5
+
6
+
7
+ PLATFORM = platform.system()
8
+ IS_WINDOWS = PLATFORM == "Windows"
9
+ IS_MACOS = PLATFORM == "Darwin"
10
+ IS_LINUX = PLATFORM == "Linux"
11
+
12
+
13
+ def detect_stata_path() -> str | None:
14
+ """Auto-detect the Stata installation directory.
15
+
16
+ Checks, in order:
17
+ 1. STATA_PATH environment variable
18
+ 2. Platform-specific default locations
19
+ """
20
+ env_path = os.environ.get("STATA_PATH")
21
+ if env_path and os.path.exists(env_path):
22
+ return env_path
23
+
24
+ if IS_MACOS:
25
+ for candidate in [
26
+ "/Applications/Stata",
27
+ "/Applications/StataNow",
28
+ "/Applications/Stata18",
29
+ "/Applications/Stata17",
30
+ ]:
31
+ if os.path.exists(candidate):
32
+ return candidate
33
+
34
+ elif IS_WINDOWS:
35
+ for version in ["18", "17", "16"]:
36
+ for prefix in [r"C:\Program Files\Stata", r"C:\Program Files (x86)\Stata"]:
37
+ candidate = prefix + version
38
+ if os.path.exists(candidate):
39
+ return candidate
40
+
41
+ elif IS_LINUX:
42
+ for candidate in ["/usr/local/stata18", "/usr/local/stata17", "/usr/local/stata"]:
43
+ if os.path.exists(candidate):
44
+ return candidate
45
+
46
+ return None
47
+
48
+
49
+ def get_pystata_path(stata_path: str) -> str | None:
50
+ """Return the pystata utilities directory inside a Stata installation."""
51
+ utilities = os.path.join(stata_path, "utilities")
52
+ pystata = os.path.join(utilities, "pystata")
53
+ if os.path.isdir(pystata):
54
+ return pystata
55
+ if os.path.isdir(utilities):
56
+ return utilities
57
+ return None
58
+
59
+
60
+ def normalize_path(path: str) -> str:
61
+ """Normalize a file path for the current platform."""
62
+ if not path:
63
+ return path
64
+ normalized = os.path.normpath(path)
65
+ if IS_WINDOWS and "/" in normalized:
66
+ normalized = normalized.replace("/", "\\")
67
+ return normalized
68
+
69
+
70
+ def join_line_continuations(code: str) -> str:
71
+ """Join Stata ``///`` line continuations into single logical lines."""
72
+ raw_lines = code.splitlines()
73
+ joined: list[str] = []
74
+ current = ""
75
+ for raw_line in raw_lines:
76
+ stripped = raw_line.rstrip()
77
+ if stripped.endswith("///"):
78
+ current += stripped[:-3].rstrip() + " "
79
+ else:
80
+ current += raw_line
81
+ joined.append(current)
82
+ current = ""
83
+ if current:
84
+ joined.append(current)
85
+ return "\n".join(joined)
@@ -0,0 +1,338 @@
1
+ Metadata-Version: 2.4
2
+ Name: stata-cli
3
+ Version: 0.2.0
4
+ Summary: Command-line interface for running Stata commands via PyStata
5
+ License: MIT
6
+ Keywords: stata,cli,statistics,data-science
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: click>=8.0
10
+ Provides-Extra: data
11
+ Requires-Dist: numpy; extra == "data"
12
+ Requires-Dist: pandas; extra == "data"
13
+
14
+ # stata-cli
15
+
16
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
17
+ [![Python Version](https://img.shields.io/badge/python-%3E%3D3.9-blue.svg)](https://www.python.org/)
18
+ [![npm version](https://img.shields.io/npm/v/stata-cli.svg)](https://www.npmjs.com/package/stata-cli)
19
+
20
+ [中文版](README.zh.md) | [English](README.md)
21
+
22
+ A command-line interface for [Stata](https://www.stata.com/) via PyStata — built for humans and AI Agents. Run Stata code, `.do` files, view data, get help, and export graphs, all from the terminal. Includes a daemon mode for sub-second execution.
23
+
24
+ [Install](#installation--quick-start) · [AI Agent](#quick-start-ai-agent) · [Commands](#commands) · [Daemon](#daemon-mode) · [Advanced](#advanced-usage) · [Contributing](#contributing)
25
+
26
+ ## Why stata-cli?
27
+
28
+ - **Agent-Native Design** — Structured JSON output, exit codes, and a [SKILL.md](SKILL.md) definition out of the box — AI Agents can operate Stata with zero extra setup
29
+ - **Sub-Second Execution** — Daemon mode keeps PyStata alive in the background, reducing startup from ~2-3s to ~85ms (35x speedup)
30
+ - **Full Coverage** — Run code, execute `.do` files, view data, browse help, export graphs, interrupt execution — everything you need from one binary
31
+ - **AI-Friendly & Optimized** — Compact output mode, token limit management, structured JSON responses, and graph auto-naming — designed for Agent tool-use
32
+ - **Open Source, Zero Barriers** — MIT license, ready to use, just `pip install`
33
+ - **Up and Running in Seconds** — Auto-detects your Stata installation, from install to first command in 2 steps
34
+
35
+ ## Features
36
+
37
+ | Category | Capabilities |
38
+ |----------|-------------|
39
+ | **Run Code** | Execute inline Stata code, multi-line blocks, or pipe from stdin |
40
+ | **Do Files** | Run `.do` files with `///` line continuation support and graph auto-naming |
41
+ | **Data Viewer** | View current dataset as JSON with `if`-condition filtering and row limits |
42
+ | **Help System** | Browse Stata help topics with SMCL-to-plain-text conversion |
43
+ | **Graph Export** | Auto-detect and export graphs as PNG to `~/.stata-cli/graphs/` |
44
+ | **Daemon Mode** | Persistent background process for sub-second execution via Unix socket |
45
+ | **Output Control** | Compact mode, JSON output, token limit management with full-output file save |
46
+ | **Interruption** | Send break signal to stop long-running commands |
47
+
48
+ ## Installation & Quick Start
49
+
50
+ ### Requirements
51
+
52
+ - **Stata 17+** installed on your machine (provides the PyStata library)
53
+ - Python 3.9+
54
+
55
+ ### Quick Start (Human Users)
56
+
57
+ #### Install
58
+
59
+ Choose **one** of the following methods:
60
+
61
+ **Option 1 — From pip (recommended):**
62
+
63
+ ```bash
64
+ pip install stata-cli
65
+ ```
66
+
67
+ **Option 2 — From npm / npx (zero Python setup):**
68
+
69
+ ```bash
70
+ # One-shot usage
71
+ npx stata-cli run "display 1+1"
72
+
73
+ # Global install
74
+ npm install -g stata-cli
75
+ ```
76
+
77
+ The npm package is a thin wrapper that delegates to `uvx`, `pipx`, or `python3`.
78
+
79
+ **Option 3 — From source:**
80
+
81
+ ```bash
82
+ git clone https://github.com/ashuiGordon/stata-cli.git
83
+ cd stata-cli
84
+ pip install -e ".[data]"
85
+ ```
86
+
87
+ #### Use
88
+
89
+ ```bash
90
+ # 1. Verify Stata is detected
91
+ stata-cli detect
92
+
93
+ # 2. Run your first command
94
+ stata-cli run "display 1+1"
95
+
96
+ # 3. Start daemon for fast execution
97
+ stata-cli daemon start
98
+ stata-cli run "sysuse auto, clear" # ~85ms!
99
+ ```
100
+
101
+ ## Quick Start (AI Agent)
102
+
103
+ > The following steps are for AI Agents calling `stata-cli` via the Bash tool.
104
+
105
+ **Step 1 — Install**
106
+
107
+ ```bash
108
+ pip install stata-cli
109
+ ```
110
+
111
+ **Step 2 — Verify Stata path**
112
+
113
+ ```bash
114
+ stata-cli detect
115
+ ```
116
+
117
+ **Step 3 — Start daemon (recommended)**
118
+
119
+ ```bash
120
+ stata-cli daemon start
121
+ ```
122
+
123
+ **Step 4 — Run commands**
124
+
125
+ ```bash
126
+ # Inline code
127
+ stata-cli run "sysuse auto, clear
128
+ regress price mpg weight
129
+ predict yhat"
130
+
131
+ # Structured JSON output
132
+ stata-cli --json run "summarize price"
133
+
134
+ # View data
135
+ stata-cli data --if "price>10000" --rows 50
136
+
137
+ # Lookup command syntax
138
+ stata-cli help regress
139
+ ```
140
+
141
+ ## Commands
142
+
143
+ ### `run` — Execute Stata Code
144
+
145
+ ```bash
146
+ stata-cli run "sysuse auto, clear"
147
+
148
+ # Multi-line
149
+ stata-cli run "sysuse auto, clear
150
+ summarize price mpg
151
+ regress price mpg weight"
152
+
153
+ # Pipe from stdin
154
+ echo "display 42" | stata-cli run -
155
+ ```
156
+
157
+ ### `do` — Execute a .do File
158
+
159
+ ```bash
160
+ stata-cli do analysis.do
161
+ stata-cli --compact do long_script.do
162
+ ```
163
+
164
+ Do files are preprocessed: `///` line continuations are joined, and unnamed graph commands are auto-named for reliable export.
165
+
166
+ ### `data` — View Current Dataset
167
+
168
+ ```bash
169
+ stata-cli data
170
+ stata-cli data --if "price>5000" --rows 50
171
+ ```
172
+
173
+ Returns the current dataset as JSON with columns, data, types, and row counts.
174
+
175
+ ### `help` — Browse Stata Help
176
+
177
+ ```bash
178
+ stata-cli help regress
179
+ stata-cli help summarize
180
+ ```
181
+
182
+ Displays help as plain text (SMCL markup is automatically converted).
183
+
184
+ ### `stop` — Interrupt Execution
185
+
186
+ ```bash
187
+ stata-cli stop
188
+ ```
189
+
190
+ Sends a break signal to the running Stata command (daemon mode).
191
+
192
+ ### `detect` — Find Stata Installation
193
+
194
+ ```bash
195
+ stata-cli detect
196
+ ```
197
+
198
+ Prints the auto-detected Stata installation path.
199
+
200
+ ## Daemon Mode
201
+
202
+ The daemon keeps PyStata alive in the background — reduces execution time from **~2-3s to ~85ms** (35x speedup).
203
+
204
+ ```bash
205
+ stata-cli daemon start # Start background daemon
206
+ stata-cli run "display 1" # Fast — auto-routes through daemon
207
+ stata-cli daemon status # Check daemon state (PID, uptime, idle)
208
+ stata-cli daemon restart # Clean restart (reset Stata state)
209
+ stata-cli daemon stop # Shut down
210
+ ```
211
+
212
+ | Command | Description |
213
+ |---------|-------------|
214
+ | `daemon start` | Start the background daemon process |
215
+ | `daemon stop` | Graceful shutdown |
216
+ | `daemon status` | Show PID, Stata path, uptime, idle time |
217
+ | `daemon restart` | Stop + start (clean Stata state) |
218
+
219
+ Commands auto-route through the daemon when it is running. Use `--no-daemon` to force direct execution.
220
+
221
+ The daemon auto-shuts down after 1 hour of inactivity (configurable with `--idle-timeout`).
222
+
223
+ ## Advanced Usage
224
+
225
+ ### Global Options
226
+
227
+ | Option | Description | Default |
228
+ |--------|-------------|---------|
229
+ | `--stata-path PATH` | Stata installation directory | auto-detected |
230
+ | `--edition [mp\|se\|be]` | Stata edition | `mp` |
231
+ | `--compact` | Strip verbose output noise | off |
232
+ | `--json` | Structured JSON output | off |
233
+ | `--timeout SECONDS` | Execution timeout | 600 |
234
+ | `--max-tokens N` | Max output tokens (0=unlimited) | 0 |
235
+ | `--no-daemon` | Force direct execution | off |
236
+ | `--graphs-dir PATH` | Graph export directory | `~/.stata-cli/graphs/` |
237
+
238
+ ### JSON Output
239
+
240
+ ```bash
241
+ stata-cli --json run "display 1+1"
242
+ ```
243
+
244
+ ```json
245
+ {
246
+ "success": true,
247
+ "output": ". display 1+1\n2",
248
+ "error": "",
249
+ "execution_time": 0.04,
250
+ "return_code": 0,
251
+ "extra": {}
252
+ }
253
+ ```
254
+
255
+ | Field | Type | Description |
256
+ |-------|------|-------------|
257
+ | `success` | bool | Whether the command succeeded |
258
+ | `output` | string | Stata output text |
259
+ | `error` | string | Error message (if any) |
260
+ | `execution_time` | float | Seconds elapsed |
261
+ | `return_code` | int | Stata r-code (0 = ok) |
262
+ | `extra` | dict | May contain `graphs` list with exported file paths |
263
+
264
+ ### Graph Export
265
+
266
+ When Stata code creates graphs, they are automatically detected and exported as PNG:
267
+
268
+ ```bash
269
+ stata-cli run "sysuse auto, clear
270
+ scatter price mpg"
271
+ ```
272
+
273
+ ```
274
+ [graph] graph1: /Users/you/.stata-cli/graphs/exec-.../graph1.png
275
+ ```
276
+
277
+ In JSON mode, graph paths appear under `extra.graphs`.
278
+
279
+ ### Token Limit Management
280
+
281
+ For long outputs, use `--max-tokens` to truncate and save the full output to a file:
282
+
283
+ ```bash
284
+ stata-cli --max-tokens 500 run "sysuse auto, clear
285
+ describe"
286
+ ```
287
+
288
+ When output exceeds the limit, a preview is shown with a path to the full saved output.
289
+
290
+ ### Environment Variables
291
+
292
+ | Variable | Description |
293
+ |----------|-------------|
294
+ | `STATA_PATH` | Override Stata installation path |
295
+ | `STATA_CLI_GRAPHS_DIR` | Override graph export directory |
296
+
297
+ ### Exit Codes
298
+
299
+ | Code | Meaning |
300
+ |------|---------|
301
+ | 0 | Success |
302
+ | 1 | Stata command error |
303
+ | 2 | CLI usage error |
304
+ | 3 | Stata not found / init failure |
305
+
306
+ ## Agent Usage Pattern
307
+
308
+ ```bash
309
+ # Full analysis workflow
310
+ stata-cli run "sysuse auto, clear
311
+ summarize price mpg
312
+ regress price mpg weight
313
+ predict yhat
314
+ list make price yhat in 1/5"
315
+
316
+ # Check data after loading
317
+ stata-cli data --if "price>10000"
318
+
319
+ # Lookup command syntax
320
+ stata-cli help anova
321
+
322
+ # Compact mode for less noise
323
+ stata-cli --compact run "sysuse auto, clear
324
+ describe"
325
+
326
+ # JSON mode for structured parsing
327
+ stata-cli --json run "display 1+1"
328
+ ```
329
+
330
+ ## Contributing
331
+
332
+ Community contributions are welcome! If you find a bug or have feature suggestions, please submit an [Issue](https://github.com/ashuiGordon/stata-cli/issues) or [Pull Request](https://github.com/ashuiGordon/stata-cli/pulls).
333
+
334
+ For major changes, we recommend discussing with us first via an Issue.
335
+
336
+ ## License
337
+
338
+ This project is licensed under the **MIT License**.
@@ -0,0 +1,14 @@
1
+ stata_cli/__init__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
2
+ stata_cli/__main__.py,sha256=RGiBSB-L3q2xUw9ko3OhEGH8SGfil9JvIMAWF4fI3Cw,67
3
+ stata_cli/daemon.py,sha256=D73a9WAoXEhGzprYckBKlbVW-Zn2fLKhTtkVvvWAniw,12575
4
+ stata_cli/engine.py,sha256=qCUT3GkeutB_XvpSdMyJpMRvI7EF8m8aAsHzHLitfFM,17449
5
+ stata_cli/graph_artifacts.py,sha256=k8Ep0da0GLIqeDxM_m5haUCEHBvyqnpa2BD96ypy5JY,2805
6
+ stata_cli/main.py,sha256=4pCEnnSYJKsRgpjyTLAsO0B9dQYZPZ_azHWxEEbHmMI,11533
7
+ stata_cli/output_filter.py,sha256=JQVUNRvjTaQNYyeLg1e5RL2fEB9tj_Tz6LPmC4rHLoM,7377
8
+ stata_cli/smcl_parser.py,sha256=oVwBKQeiDqOEjAEW4yzuS9Mzey88hFnjvhlGucX7ahI,3069
9
+ stata_cli/utils.py,sha256=ZFRtbnzoyKT1jmQctzXU9TefY1X_NG2yTNSVrFV5EqU,2489
10
+ stata_cli-0.2.0.dist-info/METADATA,sha256=OnHVLr5wUwkuGnQCHc1W9wqai1vaoiaNM8--PLIiXV4,9217
11
+ stata_cli-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
12
+ stata_cli-0.2.0.dist-info/entry_points.txt,sha256=8YIfNuTXT9Uti6zjAyjoMVoQRZ0_BVgf-1o4DK4ji4o,49
13
+ stata_cli-0.2.0.dist-info/top_level.txt,sha256=CJCcs38k3GaLHggKCfYKaQ0WDsU1F5JEXwVXZnK-jhM,10
14
+ stata_cli-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ stata-cli = stata_cli.main:cli
@@ -0,0 +1 @@
1
+ stata_cli