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.
-
@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
-
This post is deleted! -
@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
-
@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?
-
@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
-
@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'])
-
@LankyDonkey I'm going to create an entry here https://github.com/omz/Pythonista-Issues/issues later today or tomorrow. I'll also create a new topic in this forum and mention @omz.
In the mean time, I may have a solution for you. I created an alternate form dialog module that you may want to try here: uidiaglogs.py
I'm still working on it. You'll want to hit the return key when modifying the Search field to dismiss the keyboard. It has never crashed when using this module.You can put uidialogs.py in the current folder and modify the import statement in your scripts.
#import dialogs from uidialogs import dialogs
-
@LankyDonkey I'm glad it's working for you. There is an updated version.
-
@LankyDonkey Issue #1 is fixed in the latest update.
I thought I had the built in form dialog fixed with one line of code
c.cells = None
, but scrolling down to 'New Genre' it still crashes.I'll look at issue #2 in my version.
-
@bosco issue #2 is fixed.
-
Just wanted to say we're encountering issues with the built-in
dialogs
module here too.My iPad is still on ipadOS 15, but one of my co-developers is using ipadOS 16 and he sees freezes followed by segmentation faults when the UI tries to show a dialog box using that module.
This is during testing of the "big move" of our codebase from pythonista3.3 to pythonista3.4 and python2 to python3, so we thought at first it was something we were doing, but based on this thread, I think it may definitely be a bug in the dialogs module.
-
@omz @LankyDonkey @shinyformica
I have created a new issue here: Pythonista-Issues #707. -
@LankyDonkey Hello!
You may want to try with a @ui.in_background decorator.@ui.in_background def search_button_tapped(self,sender): form_list_of_sections = [] search_dicts = []
Also, I have created a more complete dialogs replacement that might work for you here:
https://gist.github.com/sbbosco/cb44f88960c16a33704cc9f92980a113You can test the replacement module with this script:
import sys, os, time from datetime import datetime import ui import dialogs # from uidialogs import dialogs """ test for modified dialog module: https://gist.github.com/sbbosco/cb44f88960c16a33704cc9f92980a113 """ today = datetime.now() sections = [('Special Filters', [{'key': 'limit', 'title': 'Artist Limit (0 for None):', 'type': 'number', 'value': '30'}, {'key': 'switch', 'title': 'Switch: ', 'type': 'switch', 'value': True }, {'key': 'date', 'title': 'Date: ', 'type': 'datetime', 'format': '%m-%d-%Y %H:%m', 'style': 'inline', 'value': today }, {'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', 'value': True}, {'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'}])] def display(playlist_filter): result = dialogs.datetime_dialog(title='Date', done_button_title='Done', style='inline') print('result', result) print('form dialog standard') diag = dialogs.form_dialog(title = 'Song Filter', sections=sections) print('done') return diag @ui.in_background def button_tapped(sender): #result = display(None) result = dialogs.form_dialog(title = 'Song Filter', sections=sections) if result: print(result['year_to']) print(result['switch']) print(result['date']) print(result['3']) dialogs.alert('Result', 'Success') else: dialogs.alert('Result', 'Failed') if __name__ == '__main__': view = ui.View() view.name = 'Dialog Test' button = ui.Button(title='Tap me!') button.background_color = 'gray' button.tint_color = 'white' button.frame = (10, 10, 200, 100) button.action = button_tapped view.add_subview(button) view.present('fullscreen')
-
@LankyDonkey
You may be able to run your dialogs in a new thread and save the @ui.in_background for the playback.from threading import Thread, current_thread def _in_background(fn, *args, **kwargs): d1 = Thread(target=fn, args=args) d1.start() def in_background(fn): def run(*args, **kwargs): def _run(): return fn(*args, **kwargs) if current_thread().name.startswith('Dummy'): return _in_background(_run) else: return(fn(*args, **kwargs)) return run @in_background def search_button_tapped(self,sender):
-
@LankyDonkey Glad to hear it was helpful.
-
@LankyDonkey @bosco glad to see a real post, drowned in an ocean of spams
-
@cvp I agree!!! I almost give up on this forum. I hope your continued presence here indicates that your health is headed in the right direction.