Hi,
(I’ve mistakenly posted that on the devbuild thread but found that it’s a general problem, so I’m reposting here with more information).
First off, if I’m doing something illegal with project_data() I apologize and please let me know what I’m doing wrong. if not then consider this a bug report.
I reproduced this consistently on a vanilla sublime 3 3126 (with only Package Controlled installed), with the following two python scrips in my User directory (Initially I always had the issue with my test script and ‘PlainTasks’ installed, but it’s not related to that plugin. I distilled it down to the actual 10 lines needed to break this)
The issue is as follows: it seems that sometimes self.window.project_data() returns a string object instead of a dict() after I update the project data with self.window.set_project_data() (even though I make certain that a) I only do it on the main thread and b) I absolutely store a dict() object.)
code -> repo_test.py:
import sublime, sublime_plugin
import os, sys, threading
import inspect
def get_type_id_string( obj ):
type_id_string = "id: {0}, type: {1}".format( id(obj), type(obj))
return type_id_string
def debug_print( text ):
callerframerecord = inspect.stack()[1]
callerframe = callerframerecord[0]
lineno = callerframe.f_lineno
print( str(lineno) + ": [TID: {0}] -> ".format(threading.get_ident()) + ": {0}".format(text) )
class RepoThread( threading.Thread ):
def __init__(self, on_finished_callback):
threading.Thread.__init__(self)
self.on_finished_callback = on_finished_callback
def run( self ):
self.item = "asdf"
debug_print( "RepoThread.run" )
def on_done():
debug_print( "RepoThread.on_done" )
self.on_finished_callback( self.item )
sublime.set_timeout( on_done, 10 )
class RepoTestCommand(sublime_plugin.WindowCommand):
def run(self, **kwargs):
debug_print( "RepoTestCommand" )
# test setup
project_data = self.window.project_data()
debug_print( "initial pd: {0}".format( get_type_id_string(project_data)))
if not project_data:
project_data = dict()
self.window.set_project_data( project_data )
project_data = self.window.project_data()
project_data.pop( "settings", None )
self.window.set_project_data( project_data )
project_data = self.window.project_data()
debug_print( "constructor pd: {0}".format( get_type_id_string(project_data)))
thread = RepoThread( self.on_thread_done )
thread.start()
def on_thread_done( self, item ):
project_data = self.window.project_data()
debug_print( "pd: way before: {0}".format( get_type_id_string(project_data)))
project_settings = dict()
project_data[ "settings" ] = project_settings
debug_print( "pd: after set settings: {0}".format( get_type_id_string(project_data)))
project_settings["solution_file"] = item
debug_print( "pd: after update settings: {0}".format( get_type_id_string(project_data)))
self.window.set_project_data( project_data )
project_data = self.window.project_data()
debug_print( "pd: after set: {0}".format( get_type_id_string(project_data)))
project_settings = project_data[ "settings" ]
code -> break_project_data.py:
import sublime, sublime_plugin
class BreakProjectDataCommand(sublime_plugin.TextCommand):
pass
class BreakProjectDataListener(sublime_plugin.ViewEventListener):
pass
output without break_project_data.py:
36: [TID: 3392] -> : RepoTestCommand
41: [TID: 3392] -> : initial pd: id: 2150516937096, type: <class ‘dict’>
51: [TID: 3392] -> : constructor pd: id: 2150517084680, type: <class ‘dict’>
25: [TID: 18976] -> : RepoThread.run
28: [TID: 3392] -> : RepoThread.on_done
59: [TID: 3392] -> : pd: way before: id: 2150517084680, type: <class ‘dict’>
63: [TID: 3392] -> : pd: after set settings: id: 2150517084680, type: <class ‘dict’>
66: [TID: 3392] -> : pd: after update settings: id: 2150517084680, type: <class ‘dict’>
70: [TID: 3392] -> : pd: after set: id: 2150495719368, type: <class ‘dict’>
output with break_project_data.py:
36: [TID: 3392] -> : RepoTestCommand
41: [TID: 3392] -> : initial pd: id: 2150516939592, type: <class ‘dict’>
51: [TID: 3392] -> : constructor pd: id: 510181184, type: <class ‘int’>
25: [TID: 13376] -> : RepoThread.run
28: [TID: 3392] -> : RepoThread.on_done
59: [TID: 3392] -> : pd: way before: id: 2150516955912, type: <class ‘dict’>
63: [TID: 3392] -> : pd: after set settings: id: 2150516955912, type: <class ‘dict’>
66: [TID: 3392] -> : pd: after update settings: id: 2150516955912, type: <class ‘dict’>
70: [TID: 3392] -> : pd: after set: id: 510181184, type: <class ‘int’>
Traceback (most recent call last):
File “C:\Users\broom\Downloads\st\Data\Packages\User\repotest.py”, line 29, in on_done
self.on_finished_callback( self.item )
File “C:\Users\broom\Downloads\st\Data\Packages\User\repotest.py”, line 71, in on_thread_done
project_settings = project_data[ “settings” ]
TypeError: ‘int’ object is not subscriptable
as you can see, if I have break_project_data.py in my User folder, eventually the project_data object that I get back is an ‘int’ instead of a ‘dict’. This is not what the documentation says and also I only ever store a dict back into the project_data. Also, the other script involved to trigger the bug doesn’t touch the project_data at all, so I’m not sure what’s going on here.