TiesdeKok / ipystata

Enables the use of Stata together with Python via Jupyter (IPython) notebooks.
192 stars 68 forks source link

Automation support for OSX #15

Open sergiocorreia opened 8 years ago

sergiocorreia commented 8 years ago

(Just a quick note, feel free to close and -wontfix- the issue)

There is a way to have Stata automation with OS X through AppleScript commands. I don't have OS X so I can't do a PR, but there is a working Python example here:

https://github.com/andrewheiss/SublimeStataEnhanced/

TiesdeKok commented 8 years ago

I do not have OS X either but I am planning to get it up and running on a virtual machine so that I can play around with the AppleScript approach. I have used Notepad++ with a Stata plugin but that SublimeText implementation looks a lot more powerful. Thanks for sharing, it is helpful to have some reference on how to implement an interaction with Stata using AppleScript and Python. It will probably save me a lot of time!

wbuchanan commented 7 years ago

@TiesdeKok & @sergiocorreia,

I just hired a guy who works primarily in Python and both he and I are Mac users. If you need help with testing/development it would be useful for us as well; that said I don't think either of us work much with AppleScript but could still look into things.

TiesdeKok commented 7 years ago

Hi @wbuchanan, I indeed would like to get a version with AppleScript done at some point. I just have a practical problem that I currently don't have a system with OS X on it which makes development difficult. I have been thinking to try and set up a virtual environment but that seems rather tedious so I have been putting it off.

Having said that, some help with testing/development would be very appreciated. I will see what I can set-up to get us going but no promises. 😄

wbuchanan commented 7 years ago

@drewbutcher is this something you would want to look into? Basically it provide both of us with a way of using the Jupyter integration for Stata from OSX (right now it would only work on the server that you've used before).

I think the snippet that @sergiocorreia was referencing is:

if sublime.platform() == "osx":
            version, stata_app_id = get_stata_version(settings.get('stata_name'))

        if sublime.platform() == "osx" and version >= 13:
            all_text = all_text.replace('\\', '\\\\\\').replace('"', '\\"'). \
                replace('`', '\\`').replace('$', "\\$").strip()

            # Stata only allows 8192 characters.
            if len(all_text)<8192:
                # Send the command to Stata with AppleScript
                cmd = """osascript<< END
                 tell application id "{}"
                    {}
                    DoCommandAsync "{}" with addToReview
                 end tell
                 END""".format(stata_app_id, switch_focus, all_text)
                print(cmd)
                os.system(cmd)
            else:
                if sublime.ok_cancel_dialog("This selection is too long to run.\n\nWould you like to run the whole do file?", "Run complete file"):
                    self.view.window().run_command("stata_run_complete")

From https://github.com/andrewheiss/SublimeStataEnhanced/blob/master/text_2_stata.py. I'm just starting to dust off my Python chops and am not sure how far removed something like this might be from what Drew is familiar with, but could be something useful that we could try looking into so we wouldn't have to rely on Windows machines to do any of this type of work.

MalcolmWardlaw commented 6 years ago

I'm wondering if this project is still under active development. As far as I can tell, there is an identical provision for all of the Windows Automation calls that can be accessed by AppleScript, and those scripts can be wrapped into Python objects using py-applescript. This means that a fairly straightforward set of classes can be written that mirror the win32com caller, bypassing the need to make a call to the shell via osascript. I think those classes can mostly be written as drop-in replacements for the existing caller, though in truth I don't fully understand the current control flow of the program.

import applescript
class Stata:

    def __init__(self):
        self.scpt = applescript.AppleScript('''
        on ASVariableNameArray()
            tell application "StataSE" to set StataVarlist to VariableNameArray
            return StataVarlist
        end ASVariableNameArray

        on ASUtilIsStataFree()
            tell application "StataSE" to set finished to UtilIsStataFree
            return finished
        end ASUtilIsStataFree

        on ASDoCommandAsync(stataprog)
            tell application "StataSE" to DoCommandAsync stataprog
        end ASDoCommandAsync
        ''')

    def DoCommandAsync(self,stataprog):
        self.scpt.call('ASDoCommandAsync',stataprog)

    def VariableNameArray(self):
        return self.scpt.call('ASVariableNameArray')

    def UtilIsStataFree(self):
        return self.scpt.call('ASUtilIsStataFree')

sj = Stata()
sj.DoCommandAsync('''
    clear
    sysuse auto
''')
while sj.UtilIsStataFree():
    pass
print(sj.VariableNameArray())

Is it worth trying to implement this?

wbuchanan commented 6 years ago

@MalcolmWardlaw The only suggestion I would have is to try using something analogous to an Abstract Class from the Java world in the Python implementation. Ideally, the operating system should be abstracted and concrete classes for each operating system would be initialized. This way if things change between the Windows or OSX or other OS specs, the interfaces that are being used to communicate back and forth with the notebook would not change. It should make it easier to maintain the code in those instances as well.

MalcolmWardlaw commented 6 years ago

@wbuchanan Python has a provision for implementing abstract classes, but it's sort of beyond my skill level.

kylebarron commented 6 years ago

Anyone on this thread who's interested should test out the Jupyter kernel I made for Stata today that works on Mac and Linux: https://github.com/kylebarron/stata_kernel

It wraps the terminal instead of using Stata Automation, but it seems to be just as good.