def build_settings(self, req, result): self.settings = None self.settings = SettingsWithNoMenu() self.settings.on_config_change = self.on_config_change self.settings.register_type('string_long', SettingString) self.settings.register_type('num_int', SettingNumeric) self.settings.register_type('num', SettingNumeric) config = ConfigParser() print result['settings'] config.setdefaults(self.popup.device_id, result['settings']) self.settings.add_json_panel(result['name'], config, data=dumps(result['settings_format'])) self.add_widget(self.settings) buttons = BoxLayout(orientation='horizontal') buttons.add_widget( Button(text='Previous', on_release=self.popup.previous_view, height='50dp')) buttons.add_widget( Button(text='Next', on_release=self.popup.next_view, height='50dp')) self.add_widget(buttons)
def settings_func(self, p): s = Settings() config = ConfigParser() try: config.setdefaults('EVM', {'school': self.school, 'names': self.temp, 'post': self.post, 'p_col': self.color, 'im_path': self.im_path, "code1": self.code1, "code2": self.code2, 'number':self.number}) except: config.setdefaults('EVM', {'school': 'Unknown', 'names': self.temp, 'post': "Unknown", 'p_col': 'FFFFFF', 'im_path': self.im_path, "code1": "voting", "code2": "results", 'number':self.number}) s.add_json_panel('EVM', config, data = self.json) s.bind(on_config_change = self.settings_change) setting = Popup(title = "Settings", content = s) s.bind(on_close = lambda *func: self.save_settings(s)) setting.open()
def build_my_settings(settings, req, result): for settable in result: yeah_id = settable[0] settings_format = settable[1] my_settings = settable[2] print yeah_id, settings_format, my_settings config = ConfigParser() config.setdefaults(yeah_id, my_settings) settings.add_json_panel(my_settings['name'], config, data=dumps(settings_format))
def load_config(): global root, allow_uploads, port config = ConfigParser() config.read('serverconfig.ini') config.setdefaults('main', { 'root': '/sdcard', 'allow_uploads': False, 'port': 11451 }) root = pathlib.Path(config['main']['root']) allow_uploads = config.getboolean('main', 'allow_uploads') port = config.getint('main', 'port')
def __init__(self, **kwargs): super(ServerSettings, self).__init__(**kwargs) config = ConfigParser() config.read('serverconfig.ini') config.setdefaults('main', { 'root': '/sdcard', 'allow_uploads': False, 'port': 11451 }) s = SettingsWithNoMenu() s.add_json_panel('Server', config, resource_find('settings.json')) s.on_config_change = restart_server self.add_widget(s)
def build_config(self, config: ConfigParser) -> None: """ Default section, key and value for config file before save configuration. :param config: :return: """ config.setdefaults('permissions', get_permissions()) config.setdefaults('info', get_general_info()) config.setdefaults('ssid', DEFAULT_SSID) config.setdefaults('connection', DEFAULT_CONNECTION) config.setdefaults('device', DEFAULT_DEVICE)
def __init__(self, scenario_screen, block, *args, **kwargs): super(BlockSettingsPopup, self).__init__(*args, **kwargs) self.app = App.get_running_app() self.title = 'Block settings' self.block = block self.scenario_screen = scenario_screen self.settings = SettingsWithNoMenu() self.settings.on_config_change = self.on_config_change self.settings.register_type('string_long', SettingString) self.settings.register_type('num_int', SettingNumeric) self.settings.register_type('num', SettingNumeric) config = ConfigParser() config.setdefaults(block.yeah_id, block.settings) self.settings.add_json_panel(block.settings['name'], config, data=dumps(block.settings_format)) self.content = self.settings
def build_config(self, config: ConfigParser) -> None: """Public function builds self.config from src/sira.ini if it exists, otherwise sets self.config with default values and writes in src/sira.ini. [ensures]: self.config is not None [self.config has all attributes in its source file] [At least, the following attributes exist: ("Text", "user_name"), ("Text", "cmd_identifier"), ("Text", "font_size"), ("Text", "font_name"), ("Jira", "url"), ("Jira", "timeout"), ("Jira", "protocol"), ("Option", "space_completion"), ("Option", "tab_completion"), ("Option", "options_per_line"), ("Result", "max_result) ] """ text = { "cmd_identifier": ">", "font_size": "14", "font_name": "Monaco", "username": "" } jira = { "url": "lnvusjira.lenovonet.lenovo.local", "timeout": "5", "protocol": "https" } option = { "space_completion": "1", "tab_completion": "1", "options_per_line": "7" } result = {"max_result": "10"} config.setdefaults("Text", text) config.setdefaults("Jira", jira) config.setdefaults("Option", option) config.setdefaults("Result", result)
def __init__(self, **kwargs): super(MyConnectDialog, self).__init__(**kwargs) self.register_type('buttons', SettingButtons) self.register_event_type('on_connect') config = ConfigParser() config.setdefaults( 'common', { 'conf_role': 'SERVER', 'conf_transport': 'TLS', 'conf_ip': '192.168.1.220', 'conf_serport': 'COM1' }) config.setdefaults('client', { 'conf_user': '******', 'conf_cert_chain': 'myhome-bundle.crt' }) config.setdefaults('server', { 'conf_serv_cert': 'rootca.crt', 'conf_serv_key': 'secret/rootca.key' }) self.myconfig = config try: config.read("i-spy.myconfig") except: print("No i-spy.myconfig") self.add_json_panel('IO device connect', config, data=json)
def setUp(self): config = ConfigParser(name='app') config.setdefaults('fretboard', get_fretboard_defaults()) config.setdefaults('fretboard_adv', get_fretboard_adv_defaults()) config.setdefaults('window', get_window_defaults()) # config.setdefaults('midi', get_midi_defaults()) config.setdefaults('harmonic_definitions', get_harmonic_definitions_defaults()) self.tuning = P4Tuning(22) self.scale_config = Scales() self.chords_config = Chords() self.pattern_config = Patterns() self.pattern_mapping = P4TuningPatternMatcher(self.tuning, self.chords_config, self.scale_config, self.pattern_config)
def build_settings(self, req, result): self.settings = None self.settings = SettingsWithNoMenu() self.settings.on_config_change = self.on_config_change self.settings.register_type('string_long', SettingString) self.settings.register_type('num_int', SettingNumeric) self.settings.register_type('num', SettingNumeric) config = ConfigParser() print result['settings'] config.setdefaults(self.popup.device_id, result['settings']) self.settings.add_json_panel(result['name'], config, data=dumps(result['settings_format'])) self.add_widget(self.settings) buttons = BoxLayout(orientation = 'horizontal') buttons.add_widget(Button(text = 'Previous', on_release = self.popup.previous_view, height = '50dp')) buttons.add_widget(Button(text = 'Next', on_release = self.popup.next_view, height = '50dp')) self.add_widget(buttons)
def test_nominal_recording_toolchain_case(): config = ConfigParser() # Empty but OK config.setdefaults("usersettings", { "record_gyroscope": 1, "record_gps": 1, "record_microphone": 1 }) key_storage_pool = FilesystemKeyStoragePool(INTERNAL_KEYS_DIR) encryption_conf = get_encryption_conf("test") toolchain = build_recording_toolchain(config, key_storage_pool=key_storage_pool, encryption_conf=encryption_conf) sensors_manager = toolchain["sensors_manager"] data_aggregators = toolchain["data_aggregators"] tarfile_aggregators = toolchain["tarfile_aggregators"] container_storage = toolchain["container_storage"] purge_test_containers() # TODO - make this a PURGE() methods of storage!!! # CLEANUP of already existing containers # for container_name in container_storage.list_container_names(sorted=True): # container_storage._delete_container(container_name) # assert not len(container_storage) start_recording_toolchain(toolchain) time.sleep(2) stop_recording_toolchain(toolchain) for i in range(2): assert not sensors_manager.is_running for data_aggregator in data_aggregators: assert len(data_aggregator) == 0 for tarfile_aggregator in tarfile_aggregators: assert len(tarfile_aggregator) == 0 time.sleep(1) assert len(container_storage ) == 1 # Too quick recording to have container rotation (container_name, ) = container_storage.list_container_names(as_sorted=True) tarfile_bytestring = container_storage.decrypt_container_from_storage( container_name) tar_file = TarfileRecordsAggregator.read_tarfile_from_bytestring( tarfile_bytestring) tarfile_members = tar_file.getnames() assert len(tarfile_members) == 3 # Gyroscope data gyroscope_filenames = [m for m in tarfile_members if "gyroscope" in m] assert len(gyroscope_filenames) == 1 assert gyroscope_filenames[0].endswith(".json") json_bytestring = tar_file.extractfile(gyroscope_filenames[0]).read() gyroscope_data = load_from_json_bytes(json_bytestring) assert isinstance(gyroscope_data, list) assert len(gyroscope_data) >= 4 assert gyroscope_data[0] == { "rotation_rate_x": None, "rotation_rate_y": None, "rotation_rate_z": None, } # GPS data microphone_filenames = [m for m in tarfile_members if "gps" in m] assert len(microphone_filenames) == 1 assert microphone_filenames[0].endswith(".json") json_bytestring = tar_file.extractfile(microphone_filenames[0]).read() gyroscope_data = load_from_json_bytes(json_bytestring) # Fake data pushed by sensor assert gyroscope_data == [{ 'altitude': 2.2 }, { 'message_type': 'some_message_type', 'status': 'some_status_value' }] # Microphone data microphone_filenames = [m for m in tarfile_members if "microphone" in m] assert len(microphone_filenames) == 1 assert microphone_filenames[0].endswith(".mp4") mp4_bytestring = tar_file.extractfile(microphone_filenames[0]).read() assert mp4_bytestring == b"fake_microphone_recording_data"
class Settings: __defaults = { 'kivy': { 'log_level': 'debug', # TODO: Change default to info 'log_enable': 1, 'log_dir': 'logs', 'log_name': 'ps_%y-%m-%d_%_.txt', 'log_maxfiles': 100 }, 'data': { 'dir': 'C:/pressure-data/', 'ppr': 20 }, 'com': { 'port': 'COM1', 'baudrate': 9600, 'bytesize': '8', 'parity': 'None', 'stopbits': '1' }, 'calibration': { 'user_point1': 0, 'sensor_point1': 0, 'user_point2': 2, 'sensor_point2': 1024 } } def __init__(self): self.config = ConfigParser() self.widget = SettingsWithNoMenu() def load(self, filename): for k, v in self.__defaults.items(): self.config.setdefaults(k, v) self.config.read(filename) self.config.write() Config.read(filename) Logger.info('Settings: Loaded setting file: %s', filename) Logger.debug('Settings: Setting up panel') self.panel = self.widget.create_json_panel('Settings', self.config, data=self.windgetconfigdata) self.widget.children[0].add_widget(self.panel) Logger.debug('Settings: Setting options') self.setPanelOptions('port', SerialAdapter.getPortNames()) self.setPanelOptions('bytesize', SerialAdapter.BYTESIZE.keys()) self.setPanelOptions('parity', SerialAdapter.PARITY.keys()) self.setPanelOptions('stopbits', SerialAdapter.STOPBITS.keys()) def updateAvailablePorts(self): Logger.debug('Settings: Setting port options') self.setPanelOptions('port', SerialAdapter.getPortNames()) def getPanelSetting(self, key): return next( (x for x in self.panel.children if not isinstance(x, SettingTitle) and not isinstance(x, Label) and x.key == key), None) def setPanelOptions(self, key, options): s = self.getPanelSetting(key) if s != None: s.options = options def getWidget(self): return self.widget def addCallback(self, callback, section=None, key=None): Logger.debug('Settings: Adding callback: %s, %s', section, key) self.config.add_callback(callback, section, key) if key != None: callback(section, key, self.get(section, key)) def get(self, section, key): return self.config.get(section, key) def set(self, section, key, value): return self.config.set(section, key, value) def getDefault(self, section, key): return self.__defaults[section][key] def saveConfig(self): self.config.write() windgetconfigdata = """[
class MainApp(MDApp): # Language: get system locale. lang = StringProperty(locale.getdefaultlocale()[0][:2]) # For showing/hiding search widget. is_search_focused = BooleanProperty(False) is_first_started = BooleanProperty(True) app_primary_palette = StringProperty("Teal") def __init__(self, **kwargs): super().__init__(**kwargs) self.selected_dampers = [ ] # Every damper selected by MyRightCheckbox add to this list. self.all_dampers_in_container = [ ] # Consists of all adding DamperListItem. self.damper = None self.dampers = [ ] # Has all getting dampers (class Damper) from the DB. self.found_dampers = [] # Has all found in searching dampers. self.menu_sort = None self.menu_dots = None # For exit on double tap on the buttnon back. self.is_back_clicked_once = False # My config. self.config = ConfigParser() # App theme. self.primary_palette = "Teal" self.accent_palette = "Amber" self.theme_style = "Light" # To avoid multi chosen right_checkbox_lang. self.lang_checkboxes_dict = dict() # Handling the back button. Window.bind(on_keyboard=self.key_input) # The current target TextInput widget requesting the keyboard # is presented just above the soft keyboard. Window.softinput_mode = "below_target" def build_config(self, config): """Default config.""" self.config.setdefaults( "currenttheme", { "primary_palette": "Teal", "accent_palette": "Amber", "theme_style": "Light" }) self.config.setdefaults("applanguage", {"language": self.lang}) def save_config(self): """Save the App config.""" self.config.set("currenttheme", "primary_palette", self.primary_palette) self.config.set("currenttheme", "accent_palette", self.accent_palette) self.config.set("currenttheme", "theme_style", self.theme_style) self.config.set("applanguage", "language", self.lang) self.config.write() def my_load_config(self): """Load the App config.""" self.primary_palette = self.config.get("currenttheme", "primary_palette") self.accent_palette = self.config.get("currenttheme", "accent_palette") self.theme_style = self.config.get("currenttheme", "theme_style") self.lang = self.config.get("applanguage", "language") def apply_mytoolbar_theme(self): """Apply loaded theme for MyToolbar.""" self.theme_cls.primary_palette = self.primary_palette self.theme_cls.accent_palette = self.accent_palette self.theme_cls.theme_style = self.theme_style def build(self): # Loading and applying the App config. # Impossible to execute self.my_load_config() in __init__ # because of configparser.NoSectionError: No section: 'currenttheme'. self.my_load_config() # Instantiate an instance of Lang. self.tr = Lang(self.lang) self.title = self.tr._("Dampers") self.menu_items_dots = [{ "text": self.tr._("Select all"), "icon": "select-all" }, { "text": self.tr._("Cancel all selection"), "icon": "select-off" }, { "text": self.tr._("Add type"), "icon": "plus" }, { "text": self.tr._("Delete/Edit type"), "icon": "delete-outline" }, { "text": self.tr._("Add damper"), "icon": "plus" }, { "text": self.tr._("Edit selected damper"), "icon": "square-edit-outline" }, { "text": self.tr._("Delete selected dampers"), "icon": "delete-outline" }, { "text": self.tr._("Backup Database"), "icon": "content-save-outline" }, { "text": self.tr._("Restore Database"), "icon": "backup-restore" }, { "text": self.tr._("Clear DB"), "icon": "delete-forever-outline" }, { "text": self.tr._("Language"), "icon": "web" }, { "text": self.tr._("Change theme"), "icon": "theme-light-dark" }, { "text": self.tr._("Exit"), "icon": "exit-to-app" }] # Dict to process callback_menu_dots like switch in C++. self.dict_menu_dots_funcs = { self.tr._("Select all"): self.select_all, self.tr._("Cancel all selection"): self.cancel_all_selection, self.tr._("Add type"): partial(self.change_screen, "add_type_screen"), self.tr._("Delete/Edit type"): partial(self.change_screen, "delete_edit_type_screen"), self.tr._("Add damper"): partial(self.change_screen, "add_damper_screen"), self.tr._("Edit selected damper"): self.edit_selected_damper, self.tr._("Delete selected dampers"): self.show_delete_dampers_dialog, self.tr._("Backup Database"): self.choose, self.tr._("Restore Database"): partial(self.choose, False), self.tr._("Clear DB"): self.show_clear_db_dialog, self.tr._("Language"): partial(self.change_screen, "language_screen"), self.tr._("Change theme"): self.show_themepicker, self.tr._("Exit"): self.stop } self.menu_items_sort = [{ "text": self.tr._("By 'number'"), "icon": "sort-numeric" }, { "text": self.tr._("By 'location'"), "icon": "format-columns" }, { "text": self.tr._("By 'check date'"), "icon": "calendar-month" }, { "text": self.tr._("By 'is released'"), "icon": "check-outline" }, { "text": self.tr._("By 'no order'"), "icon": "not-equal-variant" } # "icon": "sort-variant-remove"} ] # Dict to process callback_menu_sort like switch in C++.. self.dict_menu_sort_funcs = { self.tr._("By 'number'"): partial(self.get_dampers, "by number"), self.tr._("By 'location'"): partial(self.get_dampers, "by location"), self.tr._("By 'check date'"): partial(self.get_dampers, "by check date"), self.tr._("By 'is released'"): partial(self.get_dampers, "by is released"), self.tr._("By 'no order'"): self.get_dampers } # Handling the back button. # Window.bind(on_keyboard=self.key_input) # The current target TextInput widget requesting the keyboard # is presented just above the soft keyboard. # Window.softinput_mode = "below_target" return Container() def on_start(self): if platform == "android": # Runtime permissions. from android.permissions import request_permissions, Permission request_permissions([ Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE ]) self.apply_mytoolbar_theme() self.screen_manager = self.root.ids["screen_manager"] self.home_screen = self.root.ids["home_screen"] self.dampers_container = self.home_screen.ids["dampers_container"] self.tf_search = self.home_screen.ids["tf_search"] self.container = self.home_screen.ids["container"] self.lang_screen = self.root.ids["language_screen"] # For passing old_damper info into the EditDamperScreen. self.edit_damper_screen = self.root.ids["edit_damper_screen"] # Creating MyToolbar dots and sort menus. self.menu_dots = MDDropdownMenu( caller=self.home_screen.ids["tb_home"].ids["ibtn_dots"], items=self.menu_items_dots, callback=self.callback_menu_dots, position="bottom", hor_growth="right", # ver_growth="down", width_mult=10) self.menu_sort = MDDropdownMenu( caller=self.home_screen.ids["tb_home"].ids["ibtn_sort"], items=self.menu_items_sort, callback=self.callback_menu_sort, position="bottom", hor_growth="right", # ver_growth="up", width_mult=7) self.change_toolbar_theme() self.add_lang_checkboxes_into_dict() self.lang_checkboxes_dict[self.lang].active = True self.get_dampers() self.is_first_started = False def add_lang_checkboxes_into_dict(self): """ Store all right_checkbox_(lang) into the lang_checkboxes_dict to control which right_checkbox is chosen. """ self.lang_checkboxes_dict["en"] = self.lang_screen.ids[ "right_checkbox_en"] self.lang_checkboxes_dict["ru"] = self.lang_screen.ids[ "right_checkbox_ru"] def on_stop(self): """Save config.""" self.save_config() def on_pause(self): return True def on_resume(self): pass def on_lang(self, instance, lang): """User changed language.""" # Skip the first tr.switch_lang # because self.tr is not defined yet. # The first switch will be in the build method: self.tr = Lang(self.lang) # after self.my_load_config(). if not self.is_first_started: self.tr.switch_lang(lang) dialog = MDDialog(title=self.tr._("Change language"), size_hint=(.7, .4), text_button_ok=self.tr._("Ok"), auto_dismiss=False, events_callback=self.stop, text=self.tr._( "You have to restart the app" "\nto change the language completely.")) dialog.open() def key_input(self, window, key, scancode, codepoint, modifier): def reset_btn_back_clicked(*args): """ Set is_back_clicked_once to False. There was no double click on the button back for exit. """ self.is_back_clicked_once = False if key == 27: # (the back button key is 27, codepoint is 270). if self.screen_manager.current != "home_screen": self.change_screen("home_screen") elif self.is_back_clicked_once: self.stop() else: self.is_back_clicked_once = True toast(self.tr._("Tap BACK again to exit"), duration=1) Clock.schedule_once(reset_btn_back_clicked, 3) return True return False def callback_menu_sort(self, instance): """ Check what item in the menu_sort pressed and do the action according pressed menu item. Actions are in the self.dict_menu_sort. """ self.dict_menu_sort_funcs.get(instance.text)() def callback_menu_dots(self, instance): """ Check what item in the menu_dots pressed and do the action according pressed menu item. Actions are in the self.dict_menu_dots. """ self.dict_menu_dots_funcs.get(instance.text)() def get_dampers(self, order="no order", *args): """ Get all dampers from the DB and store them into self.dampers. :param order: str for sorting can be: "by number", "by location", "by check date", by is released", "no order" """ self.damper = Damper() try: self.dampers = self.damper.get_dampers(order) except sqlite3.DatabaseError: toast(self.tr._("Can't get dampers from the DB")) else: # Not to show_dampers in the first start # because it'll be done in change_screen. if not self.is_first_started: self.show_dampers() def show_dampers(self, is_search=False, *args): """ Get all dampers from the DB and show them. :param args: for Clock.schedule_once(self.set_field_focus, 1) in self.clear_db :param is_search: if True show only found dampers in self.found_dampers. """ # Hide search if not search. if not is_search: self.hide_search() if self.all_dampers_in_container: for damper in self.all_dampers_in_container: self.dampers_container.remove_widget(damper) # Clear all selections. self.selected_dampers.clear() self.all_dampers_in_container.clear() # If search show only found dampers in self.found_dampers. dampers = self.found_dampers if is_search else self.dampers if self.dampers: for self.damper in dampers: # Format for output damper data. released = "Released" if self.damper.is_released else "Not released" text = "{} {}".format(self.damper.number, self.damper.location) secondary_text = "{} {}".format(self.damper.check_date, released) tertiary_text = "{} {}".format( self.damper.d_type, self.damper.notes) a_damper_list_item = DamperListItem( text=text, secondary_text=secondary_text, tertiary_text=tertiary_text) self.dampers_container.add_widget(a_damper_list_item) # Add all adding DamperListItem to the list for # getting access to right_checkbox_dampers in the future. self.all_dampers_in_container.append(a_damper_list_item) else: # Clock.schedule_once(lambda x: (toast("No dampers in the DB")), 4) toast(self.tr._("No dampers in the DB")) def show_search(self, *args): """Show search.""" self.tf_search.focused = True self.is_search_focused = True # Slide tf_search top down from .96 to .9 anim_search = Animation(top_hint_search=.9) anim_search.start(self.tf_search) # Slide container(GridLayout) top down from .9 to .84 anim_container = Animation(top_hint_container=.84) anim_container.start(self.container) def hide_search(self, *args): """Hide search.""" self.is_search_focused = False # Clear tf_search when hiding. self.tf_search.text = "" # Slide tf_search top up from .9 to .96 anim_search = Animation(top_hint_search=.96) anim_search.start(self.tf_search) # Slide container(GridLayout) top up from .84 to .9 anim_container = Animation(top_hint_container=.9) anim_container.start(self.container) def search_text_changed(self, finding_text): """ Search dampers by finding_text, add filtered dampers to the self.found_dampers and output them in self.show_dampers. :param finding_text: """ self.found_dampers = [] for self.damper in self.dampers: if (finding_text in self.damper.number or finding_text in self.damper.location or finding_text in self.damper.check_date): self.found_dampers.append(self.damper) self.show_dampers(is_search=True) def choose(self, is_backup=True, *args): """ Call plyer filechooser API to run a filechooser Activity. """ if platform == "android": from android.permissions import request_permissions, Permission, check_permission # Check if the permissions still granted. if not check_permission(Permission.WRITE_EXTERNAL_STORAGE): request_permissions([Permission.WRITE_EXTERNAL_STORAGE]) else: filechooser.open_file(on_selection=self.backup_db if is_backup else self.restore_db) else: filechooser.open_file( on_selection=self.backup_db if is_backup else self.restore_db) def backup_db(self, selection): """Backup Database.""" # chosen_dir = filechooser.choose_dir(title="Choose directory") # Doesn't work on Android (why?). chosen_dirname = os.path.dirname(selection[0]) now = datetime.now() now_datetime = ("{}-{}-{}_{}-{}-{}".format(now.year, str(now.month).zfill(2), str(now.day).zfill(2), str(now.hour).zfill(2), str(now.minute).zfill(2), str(now.second).zfill(2))) # dirname = os.path.dirname(__file__) # doesn't work on Android. dirname = os.getcwd() src_db_path = "{}{}dampers.db".format(dirname, os.sep) dst_filename = "{}{}{}_{}".format(chosen_dirname, os.sep, now_datetime, "dampers.db") try: shutil.copyfile(src_db_path, dst_filename) except OSError as err: toast(str(err)) # toast("SaveBackupError") else: toast(self.tr._("Backup file saved")) def restore_db(self, selection): """Restore Database.""" # dst_db_path = os.path.dirname(__file__) # doesn't work on Android. dst_db_path = os.getcwd() try: shutil.copyfile(selection[0], "{}{}{}".format(dst_db_path, os.sep, "dampers.db")) except OSError as err: toast(str(err)) # toast("RestoreBackupError") else: toast(self.tr._("Backup file restored")) # Get and show dampers after restoring. self.get_dampers() def show_themepicker(self, *args): picker = MDThemePicker() picker.open() picker.bind(on_dismiss=self.themepicker_dismiss) def themepicker_dismiss(self, instance): """ Changing the App primary_palette, accent_palette and theme_style. :param instance: current MDThemePicker. """ self.primary_palette = self.theme_cls.primary_palette self.accent_palette = self.theme_cls.accent_palette self.theme_style = self.theme_cls.theme_style self.change_toolbar_theme() self.save_config() def change_toolbar_theme(self): """Changing tb_primary_palette for all MyToolbars.""" self.home_screen.ids[ "tb_home"].tb_primary_palette = self.primary_palette self.root.ids["add_type_screen"].ids[ "tb_addedit"].tb_primary_palette = self.primary_palette self.root.ids["edit_type_screen"].ids[ "tb_addedit"].tb_primary_palette = self.primary_palette self.root.ids["delete_edit_type_screen"].ids[ "tb_deleteedittype"].tb_primary_palette = self.primary_palette self.root.ids["add_damper_screen"].ids[ "tb_addedit"].tb_primary_palette = self.primary_palette self.root.ids["edit_damper_screen"].ids[ "tb_addedit"].tb_primary_palette = self.primary_palette self.root.ids["language_screen"].ids[ "tb_addedit"].tb_primary_palette = self.primary_palette def change_screen(self, screen_name, *args): if screen_name == "home_screen": self.tf_search.focused = False self.tf_search.text = "" self.get_dampers() self.screen_manager.current = screen_name def show_delete_dampers_dialog(self, *args): """Show delete damper dialog.""" if self.selected_dampers: dialog = MDDialog(title=self.tr._("Delete damper"), size_hint=(.7, .4), text_button_ok=self.tr._("Delete"), text_button_cancel=self.tr._("Cancel"), auto_dismiss=False, events_callback=self.delete_selected_dampers, text=self.tr._( "This action will delete selected dampers" "\nfrom the Database." "\nDo you really want to do this?")) dialog.open() def delete_selected_dampers(self, text_of_selection, *args): """ Delete selected items from DB and _item_container. """ if text_of_selection == self.tr._("Delete"): # if self.selected_dampers: for selected_damper in self.selected_dampers: # Get the damper the_number. damper_number = selected_damper.text.split()[0] damper = Damper() try: damper.delete_damper(damper_number) except sqlite3.DatabaseError: toast("DeleteDamperError") else: self.dampers_container.remove_widget(selected_damper) toast(self.tr._("Deleted")) self.get_dampers() def edit_selected_damper(self, *args): """Edit selected damper.""" if self.selected_dampers: # if self.selected_dampers is not empty. if len(self.selected_dampers) > 1: toast(self.tr._("Select one for editing")) else: number_location = self.selected_dampers[0].text.split() checkdate_isreleased = self.selected_dampers[ 0].secondary_text.split() dtype_notes = self.selected_dampers[0].tertiary_text.split() self.edit_damper_screen.old_number = number_location[0] self.edit_damper_screen.old_location = number_location[1] self.edit_damper_screen.old_check_date = checkdate_isreleased[ 0] self.edit_damper_screen.old_is_released = True if checkdate_isreleased[ 1] == "Released" else False self.edit_damper_screen.old_d_type = dtype_notes[0] self.edit_damper_screen.old_notes = dtype_notes[1] if len( dtype_notes) == 2 else "" self.change_screen("edit_damper_screen") def show_clear_db_dialog(self, *args): """Show clear DB dialog.""" dialog = MDDialog( title=self.tr._("Clear Database"), size_hint=(.7, .4), text_button_ok=self.tr._("Clear"), text_button_cancel=self.tr._("Cancel"), auto_dismiss=False, events_callback=self.clear_db, text=self.tr._( "[color={}]This action will delete " "\n[b]ALL[/b] data from the Database." "\nDo you really want to do this?[/color]").format("#FF0000")) dialog.open() def clear_db(self, text_of_selection, *args): """Delete ALL date from the DB.""" if text_of_selection == self.tr._("Clear"): damper = Damper() try: damper.clear_db() except sqlite3.DatabaseError: toast("ClearDBError") else: toast(self.tr._("Cleared")) # Delay for showing toast("Cleared") Clock.schedule_once(self.get_dampers, 1) def select_all(self, *args): """Select all elements.""" for damper_list_item in self.all_dampers_in_container: damper_list_item.ids["right_checkbox_dampers"].active = True def cancel_all_selection(self, *args): """Cancel selection of all elements.""" for damper_list_item in self.all_dampers_in_container: damper_list_item.ids["right_checkbox_dampers"].active = False def add_into_selected_dampers(self, instance): """Add selected item into the list: selected_dampers.""" self.selected_dampers.append(instance) def del_from_selected_dampers(self, instance): """Delete selected item from the list: selected_dampers.""" self.selected_dampers.remove(instance)
def build_config(self, config: ConfigParser): config.setdefaults("customization", {"button_per_scroll": 4})
class StoryBook(Widget): # This story's title title = StringProperty(None) # The story's library library_parent = StringProperty(None) # The story's library number story_number = NumericProperty(None) # The current set page by name current_page = StringProperty("title") # The current set page by number current_page_no = NumericProperty(0) # List of all pages by name pages = ListProperty() # The parsed story config story_config = ObjectProperty(None) # The defaults file story_config_file = StringProperty(None) # Where is the title media? title_media_location = StringProperty(None) def __init__(self, **kwargs): """ Initialize starting values. Set kwargs values. Set current page to title and page number to 0. :param kwargs: title: The title of this story library: The name of this story's library story_number: This story's library number """ super(StoryBook, self).__init__(**kwargs) self.title = kwargs['title'] self.library_parent = kwargs['library'] self.story_number = kwargs['number'] self.current_page = "title" self.current_page_no = 0 self.pages = [] self.story_config_file = "" def load_story_config(self, library_dir): self.story_config = ConfigParser() story_file_loc = library_dir.joinpath(self.title + '.ini') if not story_file_loc.is_file(): self.story_config.setdefaults('metadata', get_metadata_defaults(self.title, self.library_parent)) self.story_config.setdefaults('title', get_page_defaults(self.title)) self.story_config_file = str(story_file_loc) # Set config from story's config file. self.story_config.read(str(self.story_config_file)) if self.story_config.get('metadata', 'story') != self.title: self.story_config.set('metadata', 'story', self.title) if self.story_config.get('metadata', 'library') != self.library_parent: self.story_config.set('metadata', 'library', self.library_parent) # Find the media location for this story's title page self.title_media_location = self.story_config.get('title', 'media_location') # Find all the pages self.pages = ['title'] + [x.strip() for x in self.story_config.get('metadata', 'pages').split(',')] self.story_config.write() def start_page(self): """ Updates the current page to be the first page :return: """ self.current_page_no = 0 self.current_page = self.pages[0] def next_page(self): """ Updates the current page to be the next page """ self.current_page_no = min(self.current_page_no + 1, len(self.pages) - 1) self.current_page = self.pages[self.current_page_no] def previous_page(self): """ Updates the current page to be the previous page """ self.current_page_no = min(self.current_page_no - 1, len(self.pages) - 1) self.current_page = self.pages[self.current_page_no] def get_story_value(self, page, value): return self.story_config.get(page, value) def get_title_image(self): media_location = self.get_story_value(self.pages[0], 'media_location') if len(media_location) == 0: media_location = 'images/background.png' return media_location def get_story_media(self): media_location = self.get_story_value(self.current_page, 'media_location') if len(media_location) == 0: media_location = 'images/background.png' return media_location def get_story_text(self): return self.get_story_value(self.current_page, 'text')
class RenderGUI(Widget): rend = None azimuth = NumericProperty(20.0) altitude = NumericProperty(20.0) distance_per_pixel = NumericProperty(0.0) stepsize = NumericProperty(0.0) x_pixel_offset = NumericProperty(0) y_pixel_offset = NumericProperty(0) rend_opacity = BooleanProperty(False) channel = NumericProperty(0) log_offset = NumericProperty(6.0) cbar_num = NumericProperty(10) snap = NumericProperty(0) rendermode = Mode.intensity spect_analyzer = spectAnlys.Analyzer() nlamb = NumericProperty(41) cbsize = (30, 3000) asym_sep = NumericProperty(0.0) asym_width = NumericProperty(0.0) noise_snr = NumericProperty(999.) helptext = ('Pan l/r: a/d\n' 'Tilt u/d: w/s\n' 'zoom in/out: j/k\n' 'Shift l/r: [left]/[right]\n' 'Shift u/d: [up]/[down]\n' 'Recenter shift: c\n' 'Dynamic range inc/dec: i/u\n' 'Stepsize inc/dec: ./,\n' 'Toggle opacity: o\n' 'Change timestep: [/]') initialized = False def __init__(self, rend, **kwargs): self.texture = Texture.create(size=BUF_DIMENSIONS) self.texture_size = BUF_DIMENSIONS self.cbtex = Texture.create(size=self.cbsize) super(RenderGUI, self).__init__(**kwargs) self.rend = rend self.buffer_array = np.empty(BUF_DIMENSIONS[::-1] + (4, ), dtype='uint8') self.distance_per_pixel = self.rend.distance_per_pixel self.stepsize = self.rend.stepsize self.x_pixel_offset = rend.x_pixel_offset self.y_pixel_offset = rend.y_pixel_offset self.snap = self.rend.snap self.config = ConfigParser() self.channellist = [os.path.basename(os.path.splitext(a)[0]) for a in self.rend.channellist()] self.config.setdefaults('renderer', {'rendermode': self.rendermode, 'channel': self.channellist[0], 'snap': self.rend.snap, 'nlamb': self.nlamb, 'opacity': int(self.rend_opacity), 'altitude': self.altitude, 'azimuth': self.azimuth, 'distance_per_pixel': self.distance_per_pixel, 'stepsize': self.stepsize, 'noise_snr': self.noise_snr}) self.config.setdefaults('display', {'log_offset': self.log_offset, 'cbar_num': self.cbar_num, 'asym_sep': self.asym_sep, 'asym_width': self.asym_width}) self.spanel = SettingsPanel(settings=self.s, title='Render Settings', config=self.config) self.s.interface.add_panel(self.spanel, 'Render Settings', self.spanel.uid) self.dpanel = SettingsPanel(settings=self.s, title='Display Settings', config=self.config) self.s.interface.add_panel(self.dpanel, 'Display Settings', self.dpanel.uid) self.mode_opt = SettingOptions(title='Render Mode', desc='What to simulate and display', key='rendermode', section='renderer', options=[Mode.__dict__[x] for x in dir(Mode) if not x.startswith('_')], panel=self.spanel) self.spanel.add_widget(self.mode_opt) self.chan_opt = SettingOptions(title='Channel', desc='Emissions channel to select', key='channel', section='renderer', options=self.channellist, panel=self.spanel) self.spanel.add_widget(self.chan_opt) self.snap_opt = SettingNumeric(title='Snap', desc='Snap number to select', key='snap', section='renderer', panel=self.spanel) self.spanel.add_widget(self.snap_opt) self.nlamb_opt = SettingNumeric(title='NLamb', desc='Number of frequencies to sample during spectra calculations', key='nlamb', section='renderer', panel=self.spanel) self.spanel.add_widget(self.nlamb_opt) self.opa_opt = SettingBoolean(title='Opacity', desc='Whether or not to enable opacity in the simulation', key='opacity', section='renderer', panel=self.spanel) self.spanel.add_widget(self.opa_opt) self.alt_opt = SettingNumeric(title='Altitude', desc='The POV angle above horizontal', key='altitude', section='renderer', panel=self.spanel) self.spanel.add_widget(self.alt_opt) self.azi_opt = SettingNumeric(title='Azimuth', desc='The POV angle lateral to the x-axis', key='azimuth', section='renderer', panel=self.spanel) self.spanel.add_widget(self.azi_opt) self.dpp_opt = SettingNumeric(title='Distance per Pixel', desc='Distance in simulation between pixels in km, specifies zoom', key='distance_per_pixel', section='renderer', panel=self.spanel) self.spanel.add_widget(self.dpp_opt) self.stp_opt = SettingNumeric(title='Step Size', desc='Magnitude of the integration stepsize, increase for performance', key='stepsize', section='renderer', panel=self.spanel) self.spanel.add_widget(self.stp_opt) self.noise_snr_opt = SettingNumeric(title='Spectral SNR', desc=u'Spectral signal to noise ratio, in dB\u2014to disable, set to 999', key='noise_snr', section='renderer', panel=self.spanel) self.spanel.add_widget(self.noise_snr_opt) self.range_opt = SettingNumeric(title='Dynamic Range', desc='Orders of magnitude to span in display', key='log_offset', section='display', panel=self.spanel) self.dpanel.add_widget(self.range_opt) self.cbarnum_opt = SettingNumeric(title='Colorbar Numbers', desc='Number of data points to indicate on the colorbar', key='cbar_num', section='display', panel=self.spanel) self.dpanel.add_widget(self.cbarnum_opt) self.asym_width_opt = SettingNumeric(title='Asymmetry Window Width', desc='Width of integration window, in km/s', key='asym_width', section='display', panel=self.spanel) self.dpanel.add_widget(self.asym_width_opt) self.asym_sep_opt = SettingNumeric(title='Asymmetry Window Separation', desc='Separation of integration windows, in km/s', key='asym_sep', section='display', panel=self.spanel) self.dpanel.add_widget(self.asym_sep_opt) self._keyboard_open() Window.bind(on_resize=self._on_resize) #initial update self._on_resize(Window, Window.size[0], Window.size[1]) self._saverangedialog = SaveRangeDialog(self, size_hint=(.8, .8), title="Save Range") self.initialized = True def _settings_change(self, section, key, value): ''' Called on setting panel change, updates values in renderer config ''' self._keyboard_open() if key == 'opacity': self.rend_opacity = (value == '1') elif key in ('snap', 'nlamb'): setattr(self, key, int(value)) elif key == 'channel': self.channel = self.channellist.index(value) elif key == 'rendermode': self.rendermode = value elif key in ('rendermode', 'altitude', 'azimuth', 'distance_per_pixel', 'stepsize', 'log_offset', 'cbar_num', 'asym_width', 'asym_sep', 'noise_snr'): setattr(self, key, float(value)) else: return if section == 'renderer': self.update() else: self.update_display() def _keyboard_open(self): self._keyboard = Window.request_keyboard(self._keyboard_closed, self) self._keyboard.bind(on_key_down=self._on_keyboard_down) def _keyboard_closed(self): self._keyboard.unbind(on_key_down=self._on_keyboard_down) self._keyboard = None def _on_keyboard_down(self, keyboard, keycode, text, modifiers): ''' Does stuff on some keypresses ''' if keycode[1] == 'w': # view up self.altitude += 2 elif keycode[1] == 's': # view down self.altitude -= 2 elif keycode[1] == 'a': # view left self.azimuth -= 2 elif keycode[1] == 'd': # view right self.azimuth += 2 elif keycode[1] == 'j': # zoom in self.distance_per_pixel *= 0.95 elif keycode[1] == 'k': # zoom out self.distance_per_pixel /= 0.95 elif keycode[1] == 'u': # decrease contrast, increasing dyn range self.log_offset += 0.4 self.update_display() # don't rerender, just update display return elif keycode[1] == 'i': # increase contrast if self.log_offset > 0: self.log_offset -= 0.4 self.update_display() return elif keycode[1] == 'up': # shift view up self.y_pixel_offset += 5 elif keycode[1] == 'down': # shift view down self.y_pixel_offset -= 5 elif keycode[1] == 'left': # shift view left self.x_pixel_offset -= 5 elif keycode[1] == 'right': # shift view right self.x_pixel_offset += 5 elif keycode[1] == 'c': self.x_pixel_offset = self.y_pixel_offset = 0 elif keycode[1] == ',': # decreases stepsize, increasing resolution self.stepsize *= 0.8 elif keycode[1] == '.': # increases stepsize, decreasing resolution self.stepsize /= 0.8 elif keycode[1] == '[': # go back 1 snap self.snap -= 1 elif keycode[1] == ']': # go forward 1 snap self.snap += 1 elif keycode[1] == 'o': # toggle opacity self.rend_opacity = not self.rend_opacity else: return self.alt_opt.value = str(self.altitude) self.azi_opt.value = str(self.azimuth) self.range_opt.value = str(self.log_offset) self.dpp_opt.value = str(round(self.distance_per_pixel, 6)) self.stp_opt.value = str(round(self.stepsize, 6)) self.opa_opt.value = '1' if self.rend_opacity else '0' self.snap_opt.value = str(self.rend.snap) self.update() def _on_resize(self, window, width, height): ''' Rerenders, resizes objects on window resize ''' self.rend.projection_x_size, self.rend.projection_y_size = width, height self.s.size = (self.s.size[0], height) self.cbsize = (self.cbsize[0], height - 100) self.update() def update(self, updatedisplay=True): ''' Rerenders stuff and caches it, then updates display if specified ''' if not self.initialized: return # limit some values self.azimuth = self.azimuth % 360 self.altitude = sorted((-90, self.altitude, 90))[1] self.snap = sorted(self.rend.snap_range + (self.snap,))[1] # set values in renderer, and render self.rend.distance_per_pixel = self.distance_per_pixel self.rend.stepsize = self.stepsize self.rend.y_pixel_offset = self.y_pixel_offset self.rend.x_pixel_offset = self.x_pixel_offset self.rend.set_snap(self.snap) # render appropriate data, cache it if self.rendermode == Mode.intensity: data, _ = self.get_i_render() self.raw_spectra = None self.raw_data = data else: data, dfreqs, ny0, _ = self.get_il_render() self.raw_spectra = (noisify_spectra(data, self.noise_snr), dfreqs, ny0) self.raw_data = None self.spect_analyzer.set_data(*self.raw_spectra) if updatedisplay: self.update_display() def update_display(self): ''' Rejiggers display objects if no rerendering is required ''' if self.rendermode == Mode.intensity: self.unittxt.text = 'Intensity: erg s[sup]-1[/sup] cm[sup]-2[/sup] sr[sup]-1[/sup]' elif self.rendermode == Mode.doppler_shift: self.raw_data = self.spect_analyzer.quad_regc() self.raw_data *= -CC / 1e3 / self.spect_analyzer.center_freq # convert to km/s self.unittxt.text = 'Doppler shift: km/s' elif self.rendermode == Mode.width: self.raw_data = self.spect_analyzer.fwhm() self.raw_data *= CC / 1e3 / self.spect_analyzer.center_freq # convert to km/s self.unittxt.text = 'Line width at half max: km/s' elif self.rendermode == Mode.asym: self.raw_data = self.spect_analyzer.split_integral_vel(self.asym_sep, self.asym_width, 2) self.raw_data = self.raw_data[..., 1] - self.raw_data[..., 0] self.unittxt.text = 'Intensity: erg s[sup]-1[/sup] cm[sup]-2[/sup] sr[sup]-1[/sup]' bounds = (np.nanmin(self.raw_data), np.nanmax(self.raw_data)) if bounds[0] >= 0: # use symlog-based approach starting from 0 SCALAR_MAP.set_norm(colors.SymLogNorm(bounds[1] * 0.1 ** self.log_offset)) SCALAR_MAP.set_cmap(cm.bone) SCALAR_MAP.set_clim(0, bounds[1]) else: # use symlog approach b2 = max((abs(bounds[0]), bounds[1])) SCALAR_MAP.set_cmap(SYM_MAP) SCALAR_MAP.set_norm(colors.SymLogNorm(b2 * 0.1 ** self.log_offset)) SCALAR_MAP.set_clim(-b2, b2) data = SCALAR_MAP.to_rgba(self.raw_data) * 255 # update display buffer self.buffer_array[:data.shape[0], :data.shape[1]] = data self.texture.blit_buffer(self.buffer_array.tostring(), colorfmt='rgba') # colorbar text generation self.cbtxt.text = '\n' + '\n'.join(('%.3e' % val for val in reversed(SCALAR_MAP.norm.inverse(np.linspace(0, 1, self.cbar_num))))) self.cbtxt.line_height = self.cbsize[1] / (self.cbar_num - 1) / (self.cbtxt.font_size + 3) self.cbtxt.center_y = 50 + self.cbsize[1] / 2 + self.cbtxt.font_size / 2 # colorbar generation SCALAR_MAP.set_norm(colors.NoNorm()) cb_raw = np.empty(self.cbsize[::-1]) cb_raw[:] = np.expand_dims(np.linspace(0, 1, self.cbsize[1]), 1) cb_data = SCALAR_MAP.to_rgba(cb_raw) * 255 self.cbtex.blit_buffer(cb_data.astype('uint8').tostring(), size=self.cbsize, colorfmt='rgba') def save_image(self): output_name = tkFileDialog.asksaveasfilename(title='Image Array Filename') if not output_name: return self.rend.save_irender(output_name, self.raw_data) def save_spectra(self): output_name = tkFileDialog.asksaveasfilename(title='Spectra Array Filename') if not output_name: return if self.raw_spectra is None: self.rend.distance_per_pixel = self.distance_per_pixel self.rend.stepsize = self.stepsize self.rend.y_pixel_offset = self.y_pixel_offset self.rend.x_pixel_offset = self.x_pixel_offset data, dfreqs, ny0, _ = self.get_il_render() self.raw_spectra = (noisify_spectra(data, self.noise_snr), dfreqs, ny0) self.rend.save_ilrender(output_name, self.raw_spectra) def save_range(self): self._saverangedialog.rend_choice = None self._saverangedialog.open() def _renderrangefromdialog(self, srd, choice): snap_bounds = sorted((int(srd.slider_snapmin.value), int(srd.slider_snapmax.value))) snap_skip = int(srd.slider_snapskip.value) snap_range = range(snap_bounds[0], snap_bounds[1], snap_skip) channellist = self.channellist channel_ids = [channellist.index(lib.text) for lib in srd.channelselect.adapter.selection] save_loc = srd.savefilename.text save_loct = Template(save_loc) if len(snap_range) > 1 and '${num}' not in save_loc or len(channel_ids) > 1 and '${chan}' not in save_loc: ed = ErrorDialog() ed.errortext = 'Missing "${num}" or "${chan}" in file descriptor' ed.open() return orig_mode, orig_snap, orig_channel = self.rendermode, self.snap, self.channel # if spectra is chosen, choose mode that caches spectra if choice == 'il': self.rendermode = Mode.doppler_shift for snap in snap_range: self.snap = snap for channel_id in channel_ids: self.channel = channel_id save_file = save_loct.substitute(num=str(snap), chan=channellist[channel_id]) self.update(False) if choice == 'il': self.rend.save_ilrender(save_file, self.raw_spectra) elif choice == 'i': # process spectra into raw data if necessary if self.rendermode == Mode.doppler_shift: self.raw_data = self.spect_analyzer.quad_regc() self.raw_data *= -CC / 1e3 / self.spect_analyzer.center_freq # convert to km/s elif self.rendermode == Mode.width: self.raw_data = self.spect_analyzer.fwhm() self.raw_data *= CC / 1e3 / self.spect_analyzer.center_freq # convert to km/s elif self.rendermode == Mode.asym: self.raw_data = self.spect_analyzer.split_integral_vel(self.asym_sep, self.asym_width, 2) self.raw_data = self.raw_data[..., 1] - self.raw_data[..., 0] self.rend.save_irender(save_file, self.raw_data) srd.dismiss() self.mode, self.snap, self.channel = orig_mode, orig_snap, orig_channel self.raw_data = self.raw_spectra = None self.update() def get_i_render(self): return self.rend.i_render(self.channel, self.azimuth, -self.altitude, opacity=self.rend_opacity, verbose=False) def get_il_render(self): return self.rend.il_render(self.channel, self.azimuth, -self.altitude, nlamb=self.nlamb, opacity=self.rend_opacity, verbose=False)
class App(KivyApp): def __init__(self, **kwargs): super().__init__(**kwargs) # UI self.title: str = 'Aiventure' self.sm: Optional[ScreenManager] = None self.screens: Dict[str, ClassVar] = {} # AI self.ai: Optional[AI] = None self.adventure: Optional[Adventure] = None # Threading self.threads: Dict[str, Thread] = {} # Modules self.loaded_modules: Dict[str, str] = {} self.input_filters: List[Callable[[str], str]] = [] self.output_filters: List[Callable[[str], str]] = [] self.display_filter: Optional[Callable[[List[str]], str]] = None def build(self) -> ScreenManager: """ """ self.init_mods() self.init_ui() return self.sm def build_config(self, _) -> None: """ """ self.config = ConfigParser() self.config.read('config.ini') self.config.setdefaults('general', { 'userdir': 'user', 'autosave': True }) self.config.setdefaults( 'ai', { 'timeout': 20.0, 'memory': 20, 'max_length': 60, 'beam_searches': 1, 'temperature': 0.8, 'top_k': 40, 'top_p': 0.9, 'repetition_penalty': 1.1 }) self.config.setdefaults( 'modules', { 'input_filters': 'aiventure:filters', 'output_filters': 'aiventure:filters', 'display_filter': 'aiventure:filters' }) self.config.write() def init_mods(self) -> None: """ Initializes the game's module system and loads mods based on the current configuration. """ sys.path.append(self.config.get('general', 'userdir')) for f in self.config.get('modules', 'input_filters').split(','): domain, module = f.split(':') Logger.info(f'Modules: Loading {f}.filter_input') self.input_filters += [ self.load_submodule(domain, module, 'filter_input') ] for f in self.config.get('modules', 'output_filters').split(','): domain, module = f.split(':') Logger.info(f'Modules: Loading {f}.filter_output') self.output_filters += [ self.load_submodule(domain, module, 'filter_output') ] domain, module = self.config.get('modules', 'display_filter').split(':') Logger.info(f'Modules: Loading {f}.filter_display') self.display_filter = self.load_submodule(domain, module, 'filter_display') def init_ui(self) -> None: """ Initializes the screen manager, loads all screen kivy files and their associated python modules. """ self.sm = ScreenManager() self.screens = {'menu': MenuScreen, 'play': PlayScreen} for n, s in self.screens.items(): Builder.load_file(f'aiventure/client/uix/{n}.kv') self.sm.add_widget(s(name=n)) self.sm.current = 'menu' def get_user_path(self, *args: str) -> str: """ Retrieves a path relative to the current user directory. :param args: The subdirectories / filenames in the user directory. :return: A path in the current user directory. """ return os.path.join(self.config.get('general', 'userdir'), *args) def get_model_path(self, model: str) -> str: """ Gets the path to the currently selected (but not necessarily loaded) AI model. :param model: The model within the models subdirectory. :return: The current selected model path. """ return self.get_user_path('models', model) def get_valid_models(self) -> List[str]: """ :return: A list of valid model names, inside {userdir}/models """ return [ m.name for m in os.scandir(self.get_user_path('models')) if is_model_valid(m.path) ] def get_module_path(self, domain: str, module: str) -> str: return self.get_user_path('modules', domain, f'{module}.py') def load_module(self, domain: str, module: str) -> Any: """ Loads a module and returns it (if it hasn't been loaded already). :param domain: The module domain. :param module: The module to load from the given domain. :return: The loaded module. """ k = f'{domain}:{module}' v = self.loaded_modules.get(k) if v is None: v = importlib.import_module(f'.{module}', f'modules.{domain}') self.loaded_modules[k] = v return v def load_submodule(self, domain: str, module: str, submodule: str) -> str: """ Loads a submodule (a method, class, or variable from a given module). :param domain: The module domain. :param module: The module to load from the given domain. :param submodule: The submodule to load from the given module. :return: The loaded submodule. """ m = self.load_module(domain, module) return getattr(m, submodule) # SAVING AND LOADING def save_adventure(self) -> None: """ Saves the current adventure. """ savefile = get_save_name(self.adventure.name) with open(self.get_user_path('adventures', f'{savefile}.json'), 'w') as json_file: json.dump(self.adventure.to_dict(), json_file, indent=4) def load_adventure(self) -> None: """ Loads the current adventure. """ savefile = get_save_name(self.adventure.name) with open(self.get_user_path('adventures', f'{savefile}.json'), 'r') as json_file: self.adventure.from_dict(json.load(json_file))
def test_configparser_setdefaults(): """Test the setdefaults method works as expected.""" config = ConfigParser() config.setdefaults('section', {'test': '1'}) assert config.get('section', 'test') == '1'