stata

Simple wrappers for pystata/sfi functionality

sfi is Stata’s python API, originally intended for interacting with Stata from python within Stata. As such, it can only be imported with Stata running. pystata.stata.run enables running Stata code from python.

For one thing, using wrappers removes the need to constantly import pystata and/or sfi within functions elsewhere to avoid running afoul of CI tests in an environment without Stata installed.

Simple wrappers


source

get_local


def get_local(
    name
):

https://www.stata.com/python/api17/Macro.html#sfi.Macro.getLocal


source

set_local


def set_local(
    name, value
):

https://www.stata.com/python/api17/Macro.html#sfi.Macro.setLocal


source

get_global


def get_global(
    name
):

https://www.stata.com/python/api17/Macro.html#sfi.Macro.getGlobal


source

get_scalar


def get_scalar(
    name
):

https://www.stata.com/python/api17/Scalar.html?highlight=scalar#sfi.Scalar.getValue


source

stata_formatted


def stata_formatted(
    value, s_format
):

https://www.stata.com/python/api17/SFIToolkit.html#sfi.SFIToolkit.formatValue


source

variable_names


def variable_names(
    
):

variable_names uses ‘getVarCount’ and ‘getVarName’: https://www.stata.com/python/api17/Data.html

sfi.SFIToolkit.stata("quietly gen var1 = 1")
variable_names()
['var1']

source

drop_var


def drop_var(
    name
):

https://www.stata.com/python/api17/Data.html#sfi.Data.dropVar

drop_var('var1')
variable_names()
[]

source

obs_count


def obs_count(
    
):

Count the number of observations

https://www.stata.com/python/api17/Data.html#sfi.Data.getObsTotal

obs_count()
0

source

pwd


def pwd(
    
):

https://www.stata.com/python/api17/SFIToolkit.html#sfi.SFIToolkit.getWorkingDir

pwd()[-12:]
'\\nbstata\\nbs'

source

macro_expand


def macro_expand(
    s
):

https://www.stata.com/python/api17/SFIToolkit.html#sfi.SFIToolkit.macroExpand

Running arbitrary Stata code


source

run_direct


def run_direct(
    cmds, quietly:bool=False, echo:bool=False, inline:bool=True
):

run_direct wraps the most flexible utility Stata provides to run Stata commands: pystata.stata.run

run_direct("""\
disp 1
disp 2""", echo=True)

. disp 1
1

. disp 2
2

. 

source

run_single


def run_single(
    cmd, echo:bool=False
):

run_single uses an sfi function for running a single command that is notably faster than pystata.stata.run but is less versatile and appears less resilient to errors: https://www.stata.com/python/api17/SFIToolkit.html#sfi.SFIToolkit.stata

import sfi, pystata
with Timer():
    sfi.SFIToolkit.stata("disp 0")
with Timer():
    pystata.stata.run("disp 0")
0
Elapsed time: 0.0001 seconds
0
Elapsed time: 0.0585 seconds

For example, it cannot display graphs, silently quashing them instead:

sfi.SFIToolkit.stata("sysuse lifeexp, clear")
sfi.SFIToolkit.stata("scatter gnppc lexp")
(Life expectancy, 1998)
run_direct("scatter gnppc lexp", echo=True)
. scatter gnppc lexp

Even worse, a subsequent run of sfi.SFIToolkit.stata can be affected by a previous error:

try:
    sfi.SFIToolkit.stata("disp 1 \n disp 2")
except Exception as e:
    print(repr(e))
SyntaxError('failed to execute the specified Stata command')
sfi.SFIToolkit.stata('disp "1b"')
1
 invalid name
1b

But an intervening blank run seems to set things right:

try:
    sfi.SFIToolkit.stata("disp 1 \n disp 2")
except Exception:
    sfi.SFIToolkit.stata("")
1
 invalid name
sfi.SFIToolkit.stata('disp "1b"')
1b

So run_single should only be used with care. For when it is used, in case of error-causing input code, it executes sfi.SFIToolkit.stata again (with stdout redirected) to prevent the effects of the error from persisting.

with ExceptionExpected(ex=SyntaxError):
    run_single("disp 1 \n disp 2")
run_single('disp "1b"')
1b