config

Utilities for loading Stata and nbstata

Before we can use pystata, we need to find the local Stata path (i.e., find_path) and then add pystata to sys.path (i.e., set_pystata_path) so it can be imported.

The get_config function handles nbstata configuration, more broadly.

from fastcore.test import test_eq, ExceptionExpected
import tempfile

pystata configuration

Auto-detect Stata directory and edition


source

find_dir_edition


def find_dir_edition(
    stata_path:NoneType=None
):
test_eq(find_dir_edition('C:/Program Files/Stata17/StataMP-64.exe'), ('C:/Program Files/Stata17', "mp"))
with ExceptionExpected(OSError):
    find_dir_edition('')

source

find_edition


def find_edition(
    stata_dir
):
if _find_path('') == '': test_eq(find_edition(''), "be")
find_edition('C:\\Program Files\\Stata18')
'mp'
from nbstata.misc_utils import Timer
with Timer():
    print(find_dir_edition())
('C:\\Program Files\\Stata19', 'mp')
Elapsed time: 0.0004 seconds

Initialize pystata


source

set_pystata_path


def set_pystata_path(
    stata_dir:NoneType=None
):
with Timer():
    set_pystata_path()
    import pystata
Elapsed time: 0.0031 seconds
with ExceptionExpected(): import sfi

source

launch_stata


def launch_stata(
    stata_dir:NoneType=None, edition:NoneType=None, splash:bool=True
):

We modify stata_setup to make splash screen optional

with Timer():
    launch_stata(splash=False)
    pystata.config.status()
    System information
      Python version         3.11.10
      Stata version          Stata 19.0 (MP)
      Stata library path     C:\Program Files\Stata19\mp-64.dll
      Stata initialized      True
      sfi initialized        True

    Settings
      graphic display        True
      graphic size           width = default, height = default
      graphic format         svg
      command display        default
      autocompletion         on
      streaming output       on
Elapsed time: 0.5607 seconds

sfi can only be imported after Stata is launched:

import sfi

Configure pystata graph output

https://www.stata.com/python/pystata18/config.html#pystata.config.set_graph_format


source

set_graph_format


def set_graph_format(
    gformat
):
with Timer():
    set_graph_format('png')
pystata.config.status()
Elapsed time: 0.0000 seconds
    System information
      Python version         3.11.10
      Stata version          Stata 19.0 (MP)
      Stata library path     C:\Program Files\Stata19\mp-64.dll
      Stata initialized      True
      sfi initialized        True

    Settings
      graphic display        True
      graphic size           width = default, height = default
      graphic format         png
      command display        default
      autocompletion         on
      streaming output       on
_set_graph_size('2in', '4')
pystata.config.status()
_set_graph_size('default', 'default')
    System information
      Python version         3.11.10
      Stata version          Stata 19.0 (MP)
      Stata library path     C:\Program Files\Stata19\mp-64.dll
      Stata initialized      True
      sfi initialized        True

    Settings
      graphic display        True
      graphic size           width = 2.0in, height = 4in
      graphic format         png
      command display        default
      autocompletion         on
      streaming output       on

nbstata configuration

Config file location and parsing

The XDG config path is now the default, but the old path is supported for backwards compatibility. See Issue #33.


source

old_user_config_path


def old_user_config_path(
    
):

source

xdg_user_config_path


def xdg_user_config_path(
    
):
xdg_user_config_path()
Path('C:/Users/tjhuegerich/.config/nbstata/nbstata.conf')
old_user_config_path()
Path('C:/Users/tjhuegerich/.nbstata.conf')

configparser is used to parse the config file, after which quotes are stripped from all values.

test_config_contents = """\
[nbstata]
stata_dir = 'C:\Program Files\Stata19'
edition = mp
graph_width = default
graph_height = default
echo = None
browse_auto_height = False
"""
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
    f.write(test_config_contents)
    f.flush()
    test_eq(_get_settings_from_config_file(f.name), 
            {'stata_dir': 'C:\\Program Files\\Stata19',
             'edition': 'mp',
             'graph_width': 'default',
             'graph_height': 'default',
             'echo': 'None',
             'browse_auto_height': 'False'}
           )

Config class

The Config class loads the configuration file, after which pystata may be initialized with Config.init_stata. Config then also handles configuration changes made by the %set magic (that is, StataMagics.magic_set).

The initial Config class definition is here, but additional methods are added via patch_to below.

Test config file parsing and loading

test_config_contents = "test content"
config = Config()
print(config.env)
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
    f.write(test_config_contents)
    f.flush()
    config._update_env_from_config_file(Path(f.name))
{'stata_dir': None, 'edition': None, 'splash': 'False', 'graph_format': 'png', 'graph_width': '5.5in', 'graph_height': '4in', 'echo': 'None', 'missing': '.', 'browse_auto_height': 'True'}
Configuration error in C:\Users\TJHUEG~1\AppData\Local\Temp\tmp08ob504d.txt:
    File contains no section headers.
file: 'C:\\Users\\TJHUEG~1\\AppData\\Local\\Temp\\tmp08ob504d.txt', line: 1
'test content'
test_config_contents = """\
[nbstata]
stata_dir = C:\Program Files\Stata19
edition = mp
graph_width = default
graph_height = default
echo = None
browse_auto_height = False
"""
config = Config()
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
    f.write(test_config_contents)
    f.flush()
    config._update_env_from_config_file(Path(f.name))
config.env
{'stata_dir': 'C:\\Program Files\\Stata19',
 'edition': 'mp',
 'splash': 'False',
 'graph_format': 'png',
 'graph_width': 'default',
 'graph_height': 'default',
 'echo': 'None',
 'missing': '.',
 'browse_auto_height': 'False'}

The test below reads in the configuration file for the environment in which this notebook is being run:

config = Config()
config.process_config_file()
config.env
{'stata_dir': 'C:\\Program Files\\Stata19',
 'edition': 'mp',
 'splash': 'False',
 'graph_format': 'png',
 'graph_width': 'default',
 'graph_height': 'default',
 'echo': 'None',
 'missing': '.',
 'browse_auto_height': 'False'}

Testing out error messages explaining invalid keys:

config.update({'splash': 'True'})
%set error(s):
    'splash' is only allowed in a configuration file.
config.update({'splash': 'True'}, init=True)
config.update({'not_a_key': 'True'})
%set error(s):
    'not_a_key' is not a valid setting.

Applying graph size/format config settings

The configuration file is read in prior to loading Stata (since it can contain a path to the desired Stata executable). But checking the validity of graph size configuration settings uses Stata, so that can’t be done in the same step in which the configuration file is read in. Thus, the following workaround is used: hold the read-in graph size settings until they are actually applied, reverting to previous valid settings if they don’t work:


source

Config.set_graph_size


def set_graph_size(
    init:bool=False
):

If the configuration file has invalid width/height, the error message says “Graph size not changed” even though, under the hood, the pystata graph size configuration is changing from “default” to definite measures. This behavior ensures that using the %set magic to change just one of the size values, width or height, always exhibits the behavior described in the nbstata user guide rather than the (maintained aspect ratio) behavior described in the pystata docs.

config.display_status()
config.set_graph_size(init=True)
config.display_status()
    System information
      Python version         3.11.10
      Stata version          Stata 19.0 (MP)
      Stata library path     C:\Program Files\Stata19\mp-64.dll
      Stata initialized      True
      sfi initialized        True

    Settings
      graphic display        True
      graphic size           width = default, height = default
      graphic format         png
      command display        default
      autocompletion         on
      streaming output       on

      echo                   None
      missing                .
      browse_auto_height     False
      config file path       C:\Users\tjhuegerich\.config\nbstata\nbstata.conf
    System information
      Python version         3.11.10
      Stata version          Stata 19.0 (MP)
      Stata library path     C:\Program Files\Stata19\mp-64.dll
      Stata initialized      True
      sfi initialized        True

    Settings
      graphic display        True
      graphic size           width = default, height = default
      graphic format         png
      command display        default
      autocompletion         on
      streaming output       on

      echo                   None
      missing                .
      browse_auto_height     False
      config file path       C:\Users\tjhuegerich\.config\nbstata\nbstata.conf
config.update({'graph_width': '3'})
config.set_graph_size()
graph size was (default, default), is now (3, default).
config.display_status()
config.env
    System information
      Python version         3.11.10
      Stata version          Stata 19.0 (MP)
      Stata library path     C:\Program Files\Stata19\mp-64.dll
      Stata initialized      True
      sfi initialized        True

    Settings
      graphic display        True
      graphic size           width = 3in, height = default
      graphic format         png
      command display        default
      autocompletion         on
      streaming output       on

      echo                   None
      missing                .
      browse_auto_height     False
      config file path       C:\Users\tjhuegerich\.config\nbstata\nbstata.conf
{'stata_dir': 'C:\\Program Files\\Stata19',
 'edition': 'mp',
 'splash': 'True',
 'graph_format': 'png',
 'graph_width': '3',
 'graph_height': 'default',
 'echo': 'None',
 'missing': '.',
 'browse_auto_height': 'False'}
config.update({'graph_height': '-3'})
config.set_graph_size()
config.env
Configuration error: graph height is invalid. Graph size not changed.
{'stata_dir': 'C:\\Program Files\\Stata19',
 'edition': 'mp',
 'splash': 'True',
 'graph_format': 'png',
 'graph_width': '3',
 'graph_height': 'default',
 'echo': 'None',
 'missing': '.',
 'browse_auto_height': 'False'}

source

Config.update_graph_config


def update_graph_config(
    init:bool=False
):
config.update_graph_config()

source

Config.init_stata


def init_stata(
    
):