[Python] Sublime Text 3 plugin: ValueError with Edit objects?

Discussão em 'Python' iniciado por Stack, Agosto 31, 2025.

  1. Stack

    Stack Membro Participativo

    I'm building a Sublime Text 3 plugin to shorten URLs using the goo.gl API. Bear in mind that the following code is hacked together from other plugins and tutorial code. I have no previous experience with Python.

    The plugin does actually work as it is. The URL is shortened and replaced inline. Here is the plugin code:

    import sublime
    import sublime_plugin
    import urllib.request
    import urllib.error
    import json
    import threading


    class ShortenUrlCommand(sublime_plugin.TextCommand):

    def run(self, edit):
    sels = self.view.sel()

    threads = []
    for sel in sels:
    url = self.view.substr(sel)
    thread = GooglApiCall(sel, url, 5) # Send the selection, the URL and timeout to the class
    threads.append(thread)
    thread.start()

    # Wait for threads
    for thread in threads:
    thread.join()

    self.view.sel().clear()
    self.handle_threads(edit, threads, sels)

    def handle_threads(self, edit, threads, sels, offset=0, i=0, dir=1):
    next_threads = []
    for thread in threads:
    sel = thread.sel
    result = thread.result
    if thread.is_alive():
    next_threads.append(thread)
    continue
    if thread.result == False:
    continue
    offset = self.replace(edit, thread, sels, offset)
    thread = next_threads

    if len(threads):
    before = i % 8
    after = (7) - before
    if not after:
    dir = -1
    if not before:
    dir = 1
    i += dir
    self.view.set_status("shorten_url", "[%s=%s]" % (" " * before, " " * after))
    sublime.set_timeout(lambda: self.handle_threads(edit, threads, sels, offset, i, dir), 100)
    return

    self.view.erase_status("shorten_url")
    selections = len(self.view.sel())
    sublime.status_message("URL shortener successfully ran on %s URL%s" %
    (selections, "" if selections == 1 else "s"))

    def replace(self, edit, thread, sels, offset):
    sel = thread.sel
    result = thread.result
    if offset:
    sel = sublime.Region(edit, thread.sel.begin() + offset, thread.sel.end() + offset)
    self.view.replace(edit, sel, result)
    return


    class GooglApiCall(threading.Thread):
    def __init__(self, sel, url, timeout):
    self.sel = sel
    self.url = url
    self.timeout = timeout
    self.result = None
    threading.Thread.__init__(self)

    def run(self):
    try:
    apiKey = "xxxxxxxxxxxxxxxxxxxxxxxx"
    requestUrl = "https://www.googleapis.com/urlshortener/v1/url"
    data = json.dumps({"longUrl": self.url})
    binary_data = data.encode("utf-8")
    headers = {
    "User-Agent": "Sublime URL Shortener",
    "Content-Type": "application/json"
    }
    request = urllib.request.Request(requestUrl, binary_data, headers)
    response = urllib.request.urlopen(request, timeout=self.timeout)
    self.result = json.loads(response.read().decode())
    self.result = self.result["id"]
    return

    except (urllib.error.HTTPError) as e:
    err = "%s: HTTP error %s contacting API. %s." % (__name__, str(e.code), str(e.reason))
    except (urllib.error.URLError) as e:
    err = "%s: URL error %s contacting API" % (__name__, str(e.reason))

    sublime.error_message(err)
    self.result = False



    The problem is that I get the following error in the console every time the plugin runs:

    Traceback (most recent call last):
    File "/Users/joejoinerr/Library/Application Support/Sublime Text 3/Packages/URL Shortener/url_shortener.py", line 51, in <lambda>
    sublime.set_timeout(lambda: self.handle_threads(edit, threads, sels, offset, i, dir), 100)
    File "/Users/joejoinerr/Library/Application Support/Sublime Text 3/Packages/URL Shortener/url_shortener.py", line 39, in handle_threads
    offset = self.replace(edit, thread, sels, offset)
    File "/Users/joejoinerr/Library/Application Support/Sublime Text 3/Packages/URL Shortener/url_shortener.py", line 64, in replace
    self.view.replace(edit, sel, result)
    File "/Applications/Sublime Text.app/Contents/MacOS/sublime.py", line 657, in replace
    raise ValueError("Edit objects may not be used after the TextCommand's run method has returned")
    ValueError: Edit objects may not be used after the TextCommand's run method has returned



    I'm not sure what the problem is from that error. I have done some research and I understand that the solution may be held in the answer to this question, but due to my lack of Python knowledge I can't figure out how to adapt it to my use case.

    Continue reading...

Compartilhe esta Página