Ask Your Question

How do you put a save hook into wing?

asked 2017-11-07 13:38:00 -0600

Mark Jones's avatar

updated 2019-03-13 10:06:52 -0600

Wanting to add yapf formatting on save, but I need a way to capture the save event, run the formatter, update the buffer, then call the base save.

I see mentions about a pre-save event, but not finding any details anywhere.

edit retag flag offensive close merge delete

2 Answers

Sort by » oldest newest most voted

answered 2017-11-08 07:41:00 -0600

updated 2019-03-07 08:01:36 -0600

Wingware Admin's avatar

Here's a different approach that does hook up to presave to replace the contents of the editor at save time, just before saving, with the output from yapf:

import subprocess
import wingapi

def run_yapf(doc=wingapi.kArgDocument):

  # Set to non-None to use an uninstalled copy of yapf
  kYapfDir = None
  #kYapfDir = '/Users/jpe/Documents/tmp/yapf'

  proj = wingapi.gApplication.GetProject()
  pyexec = proj.GetPythonExecutable(doc.GetFilename())

  orig_text = doc.GetText()

  argv = [pyexec, '-m', 'yapf']
  process = subprocess.Popen(argv, cwd=kYapfDir, stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  from_yapf, error_output = process.communicate(orig_text)
  if from_yapf != orig_text:

def _connect_to_document(doc):
  def _on_presave(filename, encoding):
    # Called for autosave w/ filename set to non-None
    if filename is not None:

    if doc.GetMimeType() == 'text/x-python':

  connect_id = doc.Connect('presave', _on_presave)

def _init():
  wingapi.gApplication.Connect('document-open', _connect_to_document)
  for doc in wingapi.gApplication.GetOpenDocuments():

edit flag offensive delete link more


I'm assuming at this point any possibility of undo would be lost past the save wouldn't it.

Mark Jones's avatar Mark Jones  ( 2018-02-23 14:38:00 -0600 )edit

Yea, I think so but instead of calling SetText() on the doc you could call SetSelection() on the CAPIEditor instance to select all the text and then reach through the API with


where ed is the instance of CAPIEditor.  Then one undo should return you to the pre-yapf text, but of course saving again would replace it again, etc, so more would be needed to allow saving without the replacement. 

Personally, I'd rather have a way to run yapf on the file on demand and not with every save.  Or more likely I'd just not use things like yapf since Python is extremely readable regardless of details of the formatting.

Wingware Support's avatar Wingware Support  ( 2018-02-23 14:46:00 -0600 )edit

answered 2017-11-07 16:05:00 -0600

updated 2019-03-07 08:01:08 -0600

Wingware Admin's avatar

You want the save-point signal on the CAPIDocument.  Something like this:

import wingapi

def _connect_to_document(doc):
  def _on_modified(savepoint):
    if not savepoint:
    # Execute yapf here, possibly with wingapi.gApplication.AsyncExecuteCommandLine
  connect_id = doc.Connect('save-point', _on_modified)

def _init():
  wingapi.gApplication.Connect('document-open', _connect_to_document)
  for doc in wingapi.gApplication.GetOpenDocuments():

edit flag offensive delete link more


This approach assumed that yapf would run and change the file on disk, and Wing would reload the changed file automatically afterward.  The other answer above is probably better, and is more complete in any case.

Wingware Support's avatar Wingware Support  ( 2017-11-08 07:43:00 -0600 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools



Asked: 2017-11-07 13:38:00 -0600

Seen: 512 times

Last updated: Mar 07 '19