Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Segmentation fault using dialogs
-
@LankyDonkey I'm starting a new thread for your music app issues.
I'm glad you're not crashing after disabling garbage collection. This indicates that some objects / variables that are deleted while still in use. Changing a local variable to a variable in your main class or pointing to a global variable may fix your problem without needing to disable garbage collection.
@ui.in_background def do_filter(self, sender): self.form_list_of_section = 'some data'
or
global form_list_of_section @ui.in_background def do_filter(sender): global form_list_of_section form_list_of_section = 'some data'
I create a simple script here uimusic that uses dialogs, sqlite and MPMediaQuery. You may find it useful.
-
@LankyDonkey New thread for your app.
-
Thank you Bosco - to give more detail of my dialog code i have the following setup
MAINSCRIPT.py
import FilterDialog class MainViewer(ui.View): def__init__(self): self.filter_data = dict(genre="", year=None) self.filter_button.action=handle_filter def handlefilter(self): res = FilterDialog.display(self.filter_data) if res: self.filter_data = res
FILTERDIALOG.PY
import dialogs def display(filter_data): #create form_list_sections from filter_data diag = dialogs.form_dialog(sections=form_list_of_sections) #do some verification checks and then convert data back into #filter_data format and then return
so somewhere i believe filter_data must be getting garbage collection but I am not sure why. In my case above where would i define self.filter_data to be global?
-
@LankyDonkey I just did some more testing and the segmentation fault is back in dialogs.py line 372 in done_action. So it looks like maybe the garbage collection is not the solution i thought it was. I will take a look into the uimusic.py you created and see if there is something you are doing that I can adapt in my solution.
-
@LankyDonkey
add @ui.in_backgroundclass MainViewer(ui.View): def __init__(self): self.filter_data = dict(genre="", year=None) self.filter_button.action=handle_filter @ui.in_background def handlefilter(self, sender): res = FilterDialog.display(self.filter_data) if res: self.filter_data = res
-
@bosco at the moment i have @on_main_thread but i have also decorated with @ui.in_background but the error still occurs
-
@LankyDonkey i dont really understand the on_main_thread or ui.in_background but I have tried to decorate just the methods that launch dialogs with each of them and then when that didnt work i decorated all the other methods but the problem still remains.
-
This post is deleted! -
@bosco sorry that was my mistake - it is indented and part of my MainViewer - I just made a mistake when i typed into - i do have sender in there as well but i left that out for simplicity. so code is just as you have it
-
@LankyDonkey Do you ever get the dialog error the first time or only after self.filter_data becomes more complex?
global keepme keepme = None def display(some_data): #add some data to sections global keepme keepme = form_list_of_sections print(form_list_of_sections) diag = dialogs.form_dialog(title="Filter", sections=form_list_of_sections) #format result data and return
-
@bosco i do sometimes get it the very first time i use the filter. I also get it when using simpler filters. I am not sure if this would help but i pasted a cut down copy of my app code here
It doesnt have any music playing code - its just a database and gui but it still crashes. Maybe you can see something really obvious I am doing. The code is started from the songsviewer.py file -
@LankyDonkey Great! I'll try your code.
Have you tried the global variable I put in my last post?I did get your code to crash a couple times. I'm going to be offline for a few hours, but I'll look at it later.
-
@bosco This is one change I would make.
class MyListDataSource(ui.ListDataSource): def __init__(self, items, *args, **kwargs ): ui.ListDataSource.__init__(self, items, *args, **kwargs) self.width = ui.get_screen_size()[0] self.refresh(items) def refresh(self, items): self.all_items = items['items'] self.quiz_mode = items['quiz_mode'] self.font_size=items['font_size'] #self.items = [f"{index+1}.{item['title']} {item['artist']} {item['year']} [{item['rating']}] [{item['timeplayed']}]" for index, item in enumerate(self.all_items)] self.items = [f"{item['title']} {item['artist']} {item['year']} {item['score']} {item['album']}" for index, item in enumerate(self.all_items)] class SongViewer(ui.View): def __init__(self,songs): # stuff... # define self.song_titles once self.song_titles = MyListDataSource(dict(items = self.songs, quiz_mode = False, context = None, font_size = self.font_size)) # more stuff... #!! @on_main_thread def refresh_playlist(self): if self.playlist_filter: self.songs = self.MDB.apply_filter_2(self.playlist_filter, None) self.db_songs = self.songs self.refresh_songs() def refresh_songs(self): # refresh datasource items self.song_titles.refresh(dict(items = self.songs, quiz_mode = self.quiz_mode, context = None, font_size = self.font_size)) # ui.ListDataSource will auto reload when items change # skip code below """ self.table.data_source = self.table.delegate = self.song_titles self.song_titles.action=self.cell_tapped self.info.text=f"\n{self.get_playlist_filter_string()}" self.table.reload() """
I've been testing by clicking the filter_button, changing the 'from year' and 'done'. Should that be enough to make it crash?
-
@bosco yes that would make it crash - i can make it crash by selecting any random item in filter dialog - i can also make it crash by clicking the G! button and making changes or the long button at the bottom that displays Genres and making some changes there. I will make the changes you mention above. I did add the global variable into the dialog files but it still crashes. Thank you
-
@LankyDonkey I made the changes to MyListDataSource - it still crashes but I can see this is a much better way of refreshing the data. Another strange thing I keep noticing is random items will occasionally disappear from my dialogs - for example under the charts section of the filter dialog 50s might disappear and then when i re-open it will be there. very strange.
-
@LankyDonkey Whats odd is that I can use dialogs fine and then when the app is playing some songs and even if I haven't used any dialogs for a while it will suddenly crash - could it be that using the dialogs is making the app unstable - maybe it messes with the memory structure and then a later part of the app overwrites that memory causing a seg fault. So it may not be the action I do at the time that causes the crash but a previous action that has put it into an unstable state. I don't really understand these segmentation faults but it appears to be related to memory being used that shouldnt.
-
@bosco Hi Bosco I have added additional log information into my code and I can confirm that the crash happens inside the dialogs.form_dialog() call - I have code either side of the call that writes to the database with the contents of form_list_of_sections and I can see the data is fine going into the function call. I have code immediatly after the function call to add further logging to the database but this code is never reached. To me this seems like a problem with pythonista itself as there is nothing wrong with the data going in but the function never returns - it crashes on the done button( In looking dialog.py i notice the line that it crashes on is ui.end_editing()). Would you agree with this assessment?
-
@LankyDonkey I completely agree!
I thought I had a work around several times, but it still crashes. This test replacement for FilterDialog.py uses static filter data and returns static result data. It doesn't even return the results from the dialog.If you comment out this line
#c.tableview_cell_for_row = tableview_cell_for_row
and then scroll down in the dialog and select 'Speed: S4', it crashed for me every time.
import time, pprint import dialogs import emoji sections = [ ('Special Filters', [ {'key': 'limit', 'title': 'Artist Limit (00 for None): ', 'type': 'number', 'value': '30'}, {'key': 'country_count', 'title': 'Country Count: ', 'type': 'check'} ]), ('Year Range', [ {'key': 'year_from', 'title': 'Year From: ', 'type': 'number', 'value': '1990'}, {'key': 'year_to', 'title': 'Year To: ', 'type': 'number', 'value': '2022'}, {'key': 'one_song', 'title': 'One Song: ', 'type': 'check', 'value': False}, ]), ('Rating', [ {'title': '1', 'type': 'check'}, {'title': '2', 'type': 'check'}, {'title': '3', 'type': 'check'}, {'title': '4', 'type': 'check'}, {'title': '5', 'type': 'check'}, {'title': '6', 'type': 'check'}, {'title': '7', 'type': 'check'}, {'title': '8', 'type': 'check'}, {'title': '9', 'type': 'check'}, {'title': '10', 'type': 'check'}, {'title': '11', 'type': 'check'}, {'title': '12', 'type': 'check'} ]), ('Speed', [ {'title': 'S5', 'type': 'check'}, {'title': 'S4', 'type': 'check'} ]) ] filter = {'best_years': False, 'charts': [], 'countries': [], 'country_count': False, 'genres': [], 'missing_pos': None, 'missing_song_info': False, 'occasions': [], 'one_song': False, 'popularity': [], 'pos_from': None, 'pos_to': None, 'rating': [], 'song_info': False, 'special_filters': {'best_albums': False, 'best_artists': False, 'country_count': False, 'limit': '30', 'one_hit_wonders': False}, 'speeds': [], 'sub_and': False, 'subgenres': [], 'tempos': [], 'us_pos_from': None, 'us_pos_to': None, 'xmas': False, 'year_from': '1990', 'year_to': '2022'} retaincells = {} def display(playlist_filter): def tableview_cell_for_row(tv, section, row): sel_item = c.sections[section][1][row] key = sel_item['key'] cell = c.cells[section][row] retaincells[key] = cell return cell #diag = dialogs.form_dialog(title = 'Song Filter', sections=sections) c = dialogs._FormDialogController('Song Filter', sections, done_button_title='Done') c.tableview_cell_for_row = tableview_cell_for_row c.container_view.present('sheet') c.container_view.wait_modal() if c.was_canceled: return None else: diag = c.values c.container_view = None pprint.pprint(diag) time.sleep(2) return filter
I'm going to try to create a very simple script to duplicate the issue that we can show @omz
-
@bosco Thats great that you can repeat the crash everytime - this is something I have been trying to do but no success so far as it has been random for me. I hope you can create the simple script to isolate problem as that would be a big step forward. Thanks
-
@LankyDonkey Can you confirm that this script crashes when you run it multiple times after scrolling down?
#inport gc #gc.disable() import time, pprint import dialogs import objc_util retaincells = {} try_fix = False """ Dupicate issue: set try_fix = False run script scroll to RATING section, select 3, click Done or scroll unitl RATING section is a the top of the view. (larger phone may require more scrolling. rerun script It will usually crash when run the 2nd or 3rd time. """ def cleanup(): for key in retaincells.keys(): print(2, key) objc_util.release_global(retaincells[key].objc_instance) sections = [('Special Filters', [{'key': 'limit', 'title': 'Artist Limit (0 for None):', 'type': 'number', 'value': '30'}, {'key': 'country_count', 'title': 'Country Count: ', 'type': 'check'}, {'key': 'best_artists', 'title': 'Best Artists: ', 'type': 'check'}, {'key': 'best_albums', 'title': 'Best Albums: ', 'type': 'check'}, {'key': 'best_genres', 'title': 'Best Genres: ', 'type': 'check'}, {'key': 'best_years', 'title': 'Best Years: ', 'type': 'check'}, {'key': 'best_decades', 'title': 'Best Decades: ', 'type': 'check'}, {'key': 'one_hit_wonders', 'title': 'One Hit Wonders: ', 'type': 'check'} ]), ('Year Range', [{'key': 'year_from', 'title': 'Year From:', 'type': 'number', 'value': '1990'}, {'key': 'year_to', 'title': 'Year To: ', 'type': 'number', 'value': '2022'}, {'key': 'one_song', 'title': 'One Song: ', 'type': 'check', 'value': False}, {'key': 'missing_song_info', 'title': 'Missing Song Info:', 'type': 'check', 'value': False}, {'key': 'song_info', 'title': 'Song Info:', 'type': 'check', 'value': False}, {'key': 'sub_and', 'title': 'Subgenre AND:', 'type': 'check', 'value': False}, {'key': 'xmas', 'title': 'Include Xmas Songs?', 'type': 'check', 'value': False}, {'key': 'pos_from', 'title': 'Pos From: ', 'type': 'number', 'value': ''}, {'key': 'pos_to', 'title': 'Pos To:', 'type': 'number', 'value': ''}, {'key': 'missing_pos', 'title': 'Missing Pos:', 'type': 'check', 'value': False}, {'key': 'us_pos_from', 'title': 'US Pos From: ', 'type': 'number', 'value': ''}, {'key': 'us_pos_to', 'title': 'US Pos To:', 'type': 'number', 'value': ''}]), ('Rating', [{'title': '3', 'type': 'check'}, {'title': '4', 'type': 'check'}, {'title': '5', 'type': 'check'}]), ('Speed', [{'title': 'S5', 'type': 'check'}, {'title': 'S4', 'type': 'check'}, {'title': 'S3', 'type': 'check'}, {'title': 'S2', 'type': 'check'}, {'title': 'S1', 'type': 'check'}, {'title': 'Missing', 'type': 'check'}]), ('Popularity', [{'title': '[10]', 'type': 'check'}, {'title': '[9]', 'type': 'check'}, {'title': '[8]', 'type': 'check'}, {'title': '[7]', 'type': 'check'}, {'title': '[6]', 'type': 'check'}, {'title': '[5]', 'type': 'check'}, {'title': '[4]', 'type': 'check'}, {'title': '[3]', 'type': 'check'}, {'title': '[2]', 'type': 'check'}, {'title': '[1]', 'type': 'check'}, {'title': '[0]', 'type': 'check'}]), ('Charts', [{'title': '50s', 'type': 'check'}, {'title': '60s', 'type': 'check'}, {'title': '70s', 'type': 'check'}, {'title': '80s', 'type': 'check'}, {'title': '90s', 'type': 'check'}, {'title': '2000s', 'type': 'check'}, {'title': '2010s', 'type': 'check'}, {'title': '2020s', 'type': 'check'}]), ('Genres', [{'title': 'Rock', 'type': 'check'}, {'title': 'Pop', 'type': 'check'}, {'title': 'Indie', 'type': 'check'}, {'title': 'Rap', 'type': 'check'}, {'title': 'Thrash', 'type': 'check'}, {'title': 'Country', 'type': 'check'}, {'title': 'Dance', 'type': 'check'}, {'title': 'Disco', 'type': 'check'}, {'title': 'Soul', 'type': 'check'}, {'title': 'Post-punk', 'type': 'check'}, {'title': 'Punk', 'type': 'check'}]), ('Sub Genres', [{'title': 'Aor', 'type': 'check'}, {'title': 'Modernindie', 'type': 'check'}, {'title': 'Modernrock', 'type': 'check'}, {'title': 'Summer', 'type': 'check'}, {'title': 'Classicrock', 'type': 'check'}, {'title': 'Northernsoul', 'type': 'check'}, {'title': 'Indierock', 'type': 'check'}, {'title': 'Drumnbass', 'type': 'check'}, {'title': 'Funk', 'type': 'check'}, {'title': 'Hairmetal', 'type': 'check'}, {'title': 'Blues', 'type': 'check'}, {'title': 'Reggae', 'type': 'check'}, {'title': 'Breakdance', 'type': 'check'}, {'title': 'Garage', 'type': 'check'}, {'title': 'Heavymetal', 'type': 'check'}, {'title': 'House', 'type': 'check'}, {'title': 'Cheese', 'type': 'check'}, {'title': 'Billy', 'type': 'check'}, {'title': 'Grime', 'type': 'check'}, {'title': 'Rare', 'type': 'check'}, {'title': 'Yachtrock', 'type': 'check'}, {'title': 'Synthpop', 'type': 'check'}]), ('Occasions', [{'title': 'Christmas', 'type': 'check'}, {'title': 'Bonfire', 'type': 'check'}, {'title': 'Halloween', 'type': 'check'}, {'title': 'Birthday', 'type': 'check'}]), ('Tempo', [{'title': 'Slow', 'type': 'check'}, {'title': 'Normal', 'type': 'check'}, {'title': 'Fast', 'type': 'check'}, {'title': 'Not slow', 'type': 'check'}])] xfilter = {'best_years': False, 'charts': [], 'countries': [], 'country_count': False, 'genres': [], 'missing_pos': None, 'missing_song_info': False, 'occasions': [], 'one_song': False, 'popularity': [], 'pos_from': None, 'pos_to': None, 'rating': [], 'song_info': False, 'special_filters': {'best_albums': False, 'best_artists': False, 'country_count': False, 'limit': '30', 'one_hit_wonders': False}, 'speeds': [], 'sub_and': False, 'subgenres': [], 'tempos': [], 'us_pos_from': None, 'us_pos_to': None, 'xmas': False, 'year_from': '1990', 'year_to': '2023'} def display(playlist_filter): cleanup() retaincells.clear() def tableview_cell_for_row(tv, section, row): sel_item = c.sections[section][1][row] key = sel_item['key'] cell = c.cells[section][row] retaincells[key] = cell objc_util.retain_global(cell.objc_instance) return cell if try_fix: print('form dialog semi-fix') c = dialogs._FormDialogController('Song Filter', sections, done_button_title='Done') c.tableview_cell_for_row = tableview_cell_for_row c.container_view.present('sheet') c.container_view.wait_modal() if c.was_canceled: diag = None else: diag = c.values c.container_view = None else: print('form dialog standard') diag = dialogs.form_dialog(title = 'Song Filter', sections=sections) print('done') time.sleep(1) return xfilter if __name__ == '__main__': result = display(None) print(result['year_to'])