def show_survey(): # If run for the first time, open a browser tab with a survey settings = QSettings() show_survey = settings.value("startup/show-survey", True, type=bool) if show_survey: question = QMessageBox( QMessageBox.Question, 'Orange Survey', 'We would like to know more about how our software is used.\n\n' 'Would you care to fill our short 1-minute survey?', QMessageBox.Yes | QMessageBox.No) question.setDefaultButton(QMessageBox.Yes) later = question.addButton('Ask again later', QMessageBox.NoRole) question.setEscapeButton(later) def handle_response(result): if result == QMessageBox.Yes: success = QDesktopServices.openUrl( QUrl("https://orange.biolab.si/survey/short.html")) settings.setValue("startup/show-survey", not success) else: settings.setValue("startup/show-survey", result != QMessageBox.No) question.finished.connect(handle_response) question.show() return question
def fix_set_proxy_env(): """ Set http_proxy/https_proxy environment variables (for requests, pip, ...) from user-specified settings or, if none, from system settings on OS X and from registry on Windos. """ # save default proxies so that setting can be reset global default_proxies if default_proxies is None: default_proxies = getproxies( ) # can also read windows and macos settings settings = QSettings() proxies = getproxies() for scheme in set(["http", "https"]) | set(proxies): from_settings = settings.value("network/" + scheme + "-proxy", "", type=str) from_default = default_proxies.get(scheme, "") env_scheme = scheme + '_proxy' if from_settings: os.environ[env_scheme] = from_settings elif from_default: os.environ[ env_scheme] = from_default # crucial for windows/macos support else: os.environ.pop(env_scheme, "")
def setup_notifications(): settings = QSettings() # data collection permission if not settings.value( "error-reporting/permission-requested", False, type=bool): notif = Notification(icon=QIcon( resource_filename("canvas/icons/statistics-request.png")), title="Anonymous Usage Statistics", text="Do you wish to opt-in to sharing " "statistics about how you use Orange? " "All data is anonymized and used " "exclusively for understanding how users " "interact with Orange.", accept_button_label="Allow", reject_button_label="No") def handle_permission_response(role): if role != notif.DismissRole: settings.setValue("error-reporting/permission-requested", True) if role == notif.AcceptRole: UsageStatistics.set_enabled(True) settings.setValue("error-reporting/send-statistics", True) notif.clicked.connect(handle_permission_response) canvas.notification_server_instance.registerNotification(notif)
def __quicktipOnce(self): filename = os.path.join(settings.widget_settings_dir(), "user-session-state.ini") namespace = ( "user-message-history/{0.__module__}.{0.__qualname__}".format( type(self))) session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) messages = self.UserAdviceMessages def _ispending(msg): return not session_hist.value("{}/confirmed".format( msg.persistent_id), defaultValue=False, type=bool) messages = [msg for msg in messages if _ispending(msg)] if not messages: return message = messages[self.__msgchoice % len(messages)] self.__msgchoice += 1 self.__showMessage(message) def _userconfirmed(): session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) session_hist.setValue("{}/confirmed".format(message.persistent_id), True) session_hist.sync() self.__msgwidget.accepted.connect(_userconfirmed)
def open_report(self): """ Present an 'Open report' dialog to the user, load a '.report' file (as saved by OWReport) and create a new canvas window associated with the OWReport instance. """ settings = QSettings() KEY = "report/file-dialog-dir" start_dir = settings.value(KEY, "", type=str) dlg = QFileDialog( self, windowTitle=self.tr("Open Report"), acceptMode=QFileDialog.AcceptOpen, fileMode=QFileDialog.ExistingFile, ) if os.path.isdir(start_dir): dlg.setDirectory(start_dir) dlg.setWindowModality(Qt.ApplicationModal) dlg.setNameFilters(["Report (*.report)"]) def accepted(): directory = dlg.directory().absolutePath() filename = dlg.selectedFiles()[0] settings.setValue(KEY, directory) self._open_report(filename) dlg.accepted.connect(accepted) dlg.exec()
def __quicktipOnce(self): filename = os.path.join(settings.widget_settings_dir(), "user-session-state.ini") namespace = ("user-message-history/{0.__module__}.{0.__qualname__}" .format(type(self))) session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) messages = self.UserAdviceMessages def _ispending(msg): return not session_hist.value( "{}/confirmed".format(msg.persistent_id), defaultValue=False, type=bool) messages = [msg for msg in messages if _ispending(msg)] if not messages: return message = messages[self.__msgchoice % len(messages)] self.__msgchoice += 1 self.__showMessage(message) def _userconfirmed(): session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) session_hist.setValue( "{}/confirmed".format(message.persistent_id), True) session_hist.sync() self.__msgwidget.accepted.connect(_userconfirmed)
def send_statistics(url): """Send the statistics to the remote at `url`""" import json import requests settings = QSettings() if not settings.value( "error-reporting/send-statistics", False, type=bool): log.info("Not sending usage statistics (preferences setting).") return if not UsageStatistics.is_enabled(): log.info("Not sending usage statistics (disabled).") return usage = UsageStatistics() data = usage.load() for d in data: d["Orange Version"] = d.pop("Application Version", "") try: r = requests.post(url, files={'file': json.dumps(data)}) if r.status_code != 200: log.warning( "Error communicating with server while attempting to send " "usage statistics.") return # success - wipe statistics file log.info("Usage statistics sent.") with open(usage.filename(), 'w', encoding="utf-8") as f: json.dump([], f) except (ConnectionError, requests.exceptions.RequestException): log.warning( "Connection error while attempting to send usage statistics.") except Exception: # pylint: disable=broad-except log.warning("Failed to send usage statistics.", exc_info=True)
def init(self): """ Initialize the QCoreApplication.organizationDomain, applicationName, applicationVersion and the default settings format. Should only be run once at application startup. """ QCoreApplication.setOrganizationDomain(self.OrganizationDomain) QCoreApplication.setApplicationName(self.ApplicationName) QCoreApplication.setApplicationVersion(self.ApplicationVersion) QSettings.setDefaultFormat(QSettings.IniFormat)
def setup_notifications(): settings = QSettings() # If run for the fifth time, prompt short survey show_survey = settings.value("startup/show-short-survey", True, type=bool) and \ settings.value("startup/launch-count", 0, type=int) >= 5 if show_survey: surveyDialogButtons = NotificationWidget.Ok | NotificationWidget.Close surveyDialog = NotificationWidget( icon=QIcon(gui.resource_filename("icons/information.png")), title="Survey", text="We want to understand our users better.\n" "Would you like to take a short survey?", standardButtons=surveyDialogButtons) def handle_survey_response(button): if surveyDialog.buttonRole( button) == NotificationWidget.AcceptRole: success = QDesktopServices.openUrl( QUrl("https://orange.biolab.si/survey/short.html")) settings.setValue("startup/show-short-survey", not success) elif surveyDialog.buttonRole( button) == NotificationWidget.RejectRole: settings.setValue("startup/show-short-survey", False) surveyDialog.clicked.connect(handle_survey_response) NotificationOverlay.registerNotification(surveyDialog) # data collection permission if not settings.value( "error-reporting/permission-requested", False, type=bool): permDialogButtons = NotificationWidget.Ok | NotificationWidget.Close permDialog = NotificationWidget( icon=QIcon(gui.resource_filename("../../distribute/icon-48.png")), title="Anonymous Usage Statistics", text="Do you wish to opt-in to sharing " "statistics about how you use Orange?\n" "All data is anonymized and used " "exclusively for understanding how users " "interact with Orange.", standardButtons=permDialogButtons) btnOK = permDialog.button(NotificationWidget.AcceptRole) btnOK.setText("Allow") def handle_permission_response(button): if permDialog.buttonRole(button) != permDialog.DismissRole: settings.setValue("error-reporting/permission-requested", True) if permDialog.buttonRole(button) == permDialog.AcceptRole: UsageStatistics.set_enabled(True) settings.setValue("error-reporting/send-statistics", True) permDialog.clicked.connect(handle_permission_response) NotificationOverlay.registerNotification(permDialog)
def ua_string(): settings = QSettings() is_anaconda = 'Continuum' in sys.version or 'conda' in sys.version machine_id = settings.value("reporting/machine-id", "", str) return 'Orange{orange_version}:Python{py_version}:{platform}:{conda}:{uuid}'.format( orange_version=current, py_version='.'.join(str(a) for a in sys.version_info[:3]), platform=sys.platform, conda='Anaconda' if is_anaconda else '', uuid=machine_id if settings.value("reporting/send-statistics", False, bool) else '' )
class TestQSettings_array(unittest.TestCase): filename = "" # type: str def setUp(self): self.file = tempfile.NamedTemporaryFile() self.filename = self.file.name self.settings = QSettings(self.filename, QSettings.IniFormat) def tearDown(self): self.settings.sync() del self.settings self.file.close() def test_readwrite_array(self): s = self.settings scheme = {"name": str, "price": int} items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, []) items_ = [ { "name": "apple", "price": 10 }, { "name": "pear", "price": 12 }, ] QSettings_writeArray(s, "items", items_) items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, items_) scheme = {"quality": (int, -1), **scheme} items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, [{"quality": -1, **d} for d in items_]) QSettings_writeArrayItem(s, "items", 1, { "name": "banana", "price": 5, "quality": 5 }, arraysize=2) items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, [{ "name": "apple", "price": 10, "quality": -1 }, { "name": "banana", "price": 5, "quality": 5 }])
def save_plot(data, file_formats, filename=""): _LAST_DIR_KEY = "directories/last_graph_directory" _LAST_FILTER_KEY = "directories/last_graph_filter" settings = QSettings() start_dir = settings.value(_LAST_DIR_KEY, filename) if not start_dir or \ (not os.path.exists(start_dir) and not os.path.exists(os.path.split(start_dir)[0])): start_dir = os.path.expanduser("~") last_filter = settings.value(_LAST_FILTER_KEY, "") filename, writer, filter = \ filedialogs.get_file_name(start_dir, last_filter, file_formats) if not filename: return try: writer.write(filename, data) except Exception as e: mb = QMessageBox( None, windowTitle="Error", text='Error occurred while saving file "{}": {}'.format(filename, e), detailedText=traceback.format_exc(), icon=QMessageBox.Critical) mb.exec_() else: settings.setValue(_LAST_DIR_KEY, os.path.split(filename)[0]) settings.setValue(_LAST_FILTER_KEY, filter)
def init(self): """ Initialize the QCoreApplication.organizationDomain, applicationName, applicationVersion and the default settings format. Should only be run once at application startup. """ QCoreApplication.setOrganizationDomain(self.OrganizationDomain) QCoreApplication.setApplicationName(self.ApplicationName) QCoreApplication.setApplicationVersion(self.ApplicationVersion) QSettings.setDefaultFormat(QSettings.IniFormat) app = QCoreApplication.instance() if app is not None: QCoreApplication.sendEvent(app, QEvent(QEvent.PolishRequest))
def accept(self): super().accept() F = self.DataField data = self._data.copy() if QSettings().value('error-reporting/add-scheme', True, type=bool): data[F.WIDGET_SCHEME] = data['_' + F.WIDGET_SCHEME] else: data.pop(F.WIDGET_SCHEME, None) del data['_' + F.WIDGET_SCHEME] def _post_report(data): MAX_RETRIES = 2 for _retry in range(MAX_RETRIES): try: urlopen(REPORT_POST_URL, timeout=10, data=urlencode(data).encode('utf8')) except Exception as e: if _retry == MAX_RETRIES - 1: e.__context__ = None log.exception('Error reporting failed', exc_info=e) time.sleep(10) continue break Thread(target=_post_report, args=(data, )).start()
def __init__(self, model="inception-v3", layer="penultimate", server_url='api.garaza.io:443'): super().__init__(server_url) model_settings = self._get_model_settings_confidently(model, layer) self._model = model self._layer = layer self._target_image_size = model_settings['target_image_size'] cache_file_path = self._cache_file_blueprint.format(model, layer) self._cache_file_path = join(cache_dir(), cache_file_path) self._cache_dict = self._init_cache() self._session = cachecontrol.CacheControl( requests.session(), cache=cachecontrol.caches.FileCache( join(cache_dir(), __name__ + ".ImageEmbedder.httpcache")) ) # attribute that offers support for cancelling the embedding # if ran in another thread self.cancelled = False self.machine_id = \ QSettings().value('error-reporting/machine-id', '', type=str) \ or str(uuid.getnode()) self.session_id = None
def __init__( self, model_name: str, max_parallel_requests: int, server_url: str, embedder_type: str, ) -> None: self.server_url = getenv("ORANGE_EMBEDDING_API_URL", server_url) self._model = model_name self.embedder_type = embedder_type # attribute that offers support for cancelling the embedding # if ran in another thread self._cancelled = False self.machine_id = QSettings().value( "error-reporting/machine-id", "", type=str) or str(uuid.getnode()) self.session_id = str(random.randint(1, 1e10)) self._cache = EmbedderCache(model_name) # default embedding timeouts are too small we need to increase them self.timeout = 60 self.num_parallel_requests = 0 self.max_parallel = max_parallel_requests self.content_type = None # need to be set in a class inheriting
def __init__(self): enabled = QSettings().value('add-ons/allow-conda-experimental', False, type=bool) if enabled: self.conda = self._find_conda() else: self.conda = None
def __init__(self): enabled = QSettings().value('add-ons/allow-conda', True, type=bool) if enabled: self.conda = self._find_conda() else: self.conda = None
def write_statistics(self): """ Write the statistics session to file, and clear it. """ if not self.is_enabled(): return statistics_path = self.filename() statistics = { "Date": str(datetime.now().date()), "Application Version": QCoreApplication.applicationVersion(), "Operating System": platform.system() + " " + platform.release(), "Launch Count": QSettings().value('startup/launch-count', 0, type=int), "Session": self._actions } if os.path.isfile(statistics_path): with open(statistics_path) as f: data = json.load(f) else: data = [] data.append(statistics) with open(statistics_path, 'w') as f: json.dump(data, f) self.drop_statistics()
def __init__( self, model_name: str, max_parallel_requests: int, server_url: str, embedder_type: str, ) -> None: self.server_url = getenv("ORANGE_EMBEDDING_API_URL", server_url) self._model = model_name self.embedder_type = embedder_type # remove in 3.34 self._cancelled = False self.machine_id = None try: self.machine_id = QSettings().value( "error-reporting/machine-id", "", type=str) or str( uuid.getnode()) except TypeError: self.machine_id = str(uuid.getnode()) self.session_id = str(random.randint(1, int(1e10))) self._cache = EmbedderCache(model_name) # default embedding timeouts are too small we need to increase them self.timeout = 180 self.max_parallel_requests = max_parallel_requests self.content_type = None # need to be set in a class inheriting
def swp_name(canvas): document = canvas.current_document() if document.path(): filename = os.path.basename(document.path()) dirname = os.path.dirname(document.path()) return os.path.join(dirname, '.' + filename + ".swp.p") # else it's a scratch workflow if not QSettings().value('startup/load-crashed-workflows', True, type=bool): return None global canvas_scratch_name_memo if canvas in canvas_scratch_name_memo: return canvas_scratch_name_memo[canvas] swpname = scratch_swp_base_name() i = 0 while os.path.exists(swpname + '.' + str(i)): i += 1 swpname += '.' + str(i) canvas_scratch_name_memo[canvas] = swpname return swpname
def test_settings_model(self): store = QSettings( QSettings.IniFormat, QSettings.UserScope, "biolab.si", "Orange Canvas UnitTests", ) defaults = [ config_slot("S1", bool, True, "Something"), config_slot("S2", str, "I an not a String", "Disregard the string."), ] settings = Settings(defaults=defaults, store=store) model = UserSettingsModel(settings=settings) self.assertEqual(model.rowCount(), len(settings)) view = QTreeView() view.setHeaderHidden(False) view.setModel(model) view.show() self.app.exec_()
def init(self): super().init() widget_settings_dir_cfg = environ.get_path("widget_settings_dir", "") if widget_settings_dir_cfg: # widget_settings_dir is configured via config file set_widget_settings_dir_components(widget_settings_dir_cfg, self.ApplicationVersion) canvas_settings_dir_cfg = environ.get_path("canvas_settings_dir", "") if canvas_settings_dir_cfg: # canvas_settings_dir is configured via config file QSettings.setPath(QSettings.IniFormat, QSettings.UserScope, canvas_settings_dir_cfg) for t in spec: occonfig.register_setting(*t)
def max_active(self) -> int: value = self.__max_running # type: Optional[int] if value is None: value = mapping_get(os.environ, "MAX_ACTIVE_NODES", int, None) if value is None: s = QSettings() s.beginGroup(__name__) value = s.value("max-active-nodes", defaultValue=1, type=int) if value < 0: ccount = os.cpu_count() if ccount is None: return 1 else: return max(1, ccount + value) else: return max(1, value)
def save_plot(data, file_formats, filename=""): _LAST_DIR_KEY = "directories/last_graph_directory" _LAST_FILTER_KEY = "directories/last_graph_filter" settings = QSettings() start_dir = settings.value(_LAST_DIR_KEY, filename) if not start_dir or \ (not os.path.exists(start_dir) and not os.path.exists(os.path.split(start_dir)[0])): start_dir = os.path.expanduser("~") last_filter = settings.value(_LAST_FILTER_KEY, "") filename, writer, filter = \ filedialogs.open_filename_dialog_save(start_dir, last_filter, file_formats) if not filename: return try: writer.write(filename, data) except OSError as e: mb = QMessageBox( None, windowTitle="Error", text='Error occurred while saving file "{}": {}'.format(filename, e), detailedText=traceback.format_exc(), icon=QMessageBox.Critical) mb.exec_() else: settings.setValue(_LAST_DIR_KEY, os.path.split(filename)[0]) settings.setValue(_LAST_FILTER_KEY, filter)
def save(self): fname, _ = QFileDialog.getSaveFileName( self, "File name", self._start_dir(), "Variable definitions (*.colors)") if not fname: return QSettings().setValue("colorwidget/last-location", os.path.split(fname)[0]) self._save_var_defs(fname)
def _networkAccessManagerInstance(cls): netmanager = cls._NETMANAGER_REF and cls._NETMANAGER_REF() settings = QSettings() settings.beginGroup(__name__) cache_dir = os.path.join(config.cache_dir(), "help", __name__) cache_size = settings.value("cache_size_mb", defaultValue=50, type=int) if netmanager is None: try: os.makedirs(cache_dir, exist_ok=True) except OSError: pass netmanager = QNetworkAccessManager() cache = QNetworkDiskCache() cache.setCacheDirectory(cache_dir) cache.setMaximumCacheSize(cache_size * 2**20) netmanager.setCache(cache) cls._NETMANAGER_REF = ref(netmanager) return netmanager
def show_welcome_screen(self, parent: CanvasMainWindow): """Show the initial welcome screen.""" settings = QSettings() options = self.options want_welcome = settings.value("startup/show-welcome-screen", True, type=bool) and not options.no_welcome def trigger(): if not parent.is_transient(): return swp_loaded = parent.ask_load_swp_if_exists() if not swp_loaded and want_welcome: parent.welcome_action.trigger() # On a timer to allow FileOpen events to be delivered. If so # then do not show the welcome screen. QTimer.singleShot(0, trigger)
def ua_string(): is_anaconda = 'Continuum' in sys.version or 'conda' in sys.version return 'Orange{orange_version}:Python{py_version}:{platform}:{conda}:{uuid}'.format( orange_version=current, py_version='.'.join(str(a) for a in sys.version_info[:3]), platform=sys.platform, conda='Anaconda' if is_anaconda else '', uuid=QSettings().value("error-reporting/machine-id", "", str), )
def setUp(self): self._stack = ExitStack().__enter__() # patch `_local_settings` to avoid side effects, across tests fname = self._stack.enter_context(named_file("")) s = QSettings(fname, QSettings.IniFormat) self._stack.enter_context( mock.patch.object(owcsvimport.OWCSVFileImport, "_local_settings", lambda *a: s)) self.widget = self.create_widget(owcsvimport.OWCSVFileImport)
class TestQSettings_array(unittest.TestCase): filename = "" # type: str def setUp(self): self.file = tempfile.NamedTemporaryFile() self.filename = self.file.name self.settings = QSettings(self.filename, QSettings.IniFormat) def tearDown(self): self.settings.sync() del self.settings self.file.close() def test_readwrite_array(self): s = self.settings scheme = { "name": str, "price": int } items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, []) items_ = [ {"name": "apple", "price": 10}, {"name": "pear", "price": 12}, ] QSettings_writeArray(s, "items", items_) items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, items_) scheme = { "quality": (int, -1), **scheme } items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, [{"quality": -1, **d} for d in items_]) QSettings_writeArrayItem( s, "items", 1, {"name": "banana", "price": 5, "quality": 5}, arraysize=2 ) items = QSettings_readArray(s, "items", scheme) self.assertSequenceEqual(items, [ {"name": "apple", "price": 10, "quality": -1}, {"name": "banana", "price": 5, "quality": 5} ])
def list_selected_encodings(): # type: () -> List[str] """ Return a list of all current selected encodings from user preferences. """ settings = QSettings() settings.beginGroup(SettingsGroup) res = [] for encoding, _ in ENCODING_DISPLAY_NAME: try: co = codecs.lookup(encoding) except LookupError: continue selected = settings.value(co.name, defaultValue=co.name in DEFAULT_ENCODINGS, type=bool) if selected: res.append(co.name) return res
def __init__(self, parent=None, defaults=(), path=None, store=None): super().__init__(parent) if store is None: store = QSettings() path = (path or "").rstrip("/") self.__path = path self.__defaults = dict([(slot.key, slot) for slot in defaults]) self.__store = store
def test_qsettings_type(self): """ Test if QSettings as exported by qtcompat has the 'type' parameter. """ with tempfile.NamedTemporaryFile("w+b", suffix=".ini", delete=False) as f: settings = QSettings(f.name, QSettings.IniFormat) settings.setValue("bar", "foo") self.assertEqual(settings.value("bar", type=str), "foo") settings.setValue("frob", 4) del settings settings = QSettings(f.name, QSettings.IniFormat) self.assertEqual(settings.value("bar", type=str), "foo") self.assertEqual(settings.value("frob", type=int), 4)
def init(): """ Initialize the QCoreApplication.organizationDomain, applicationName, applicationVersion and the default settings format. Will only run once. .. note:: This should not be run before QApplication has been initialized. Otherwise it can break Qt's plugin search paths. """ dist = pkg_resources.get_distribution("Orange3") version = dist.version # Use only major.minor version = ".".join(version.split(".", 2)[:2]) QCoreApplication.setOrganizationDomain("biolab.si") QCoreApplication.setApplicationName("Orange Canvas") QCoreApplication.setApplicationVersion(version) QSettings.setDefaultFormat(QSettings.IniFormat) # Make it a null op. global init init = lambda: None
def fix_set_proxy_env(): """ Set http_proxy/https_proxy environment variables (for requests, pip, ...) from user-specified settings or, if none, from system settings on OS X and from registry on Windos. """ # save default proxies so that setting can be reset global default_proxies if default_proxies is None: default_proxies = getproxies() # can also read windows and macos settings settings = QSettings() proxies = getproxies() for scheme in set(["http", "https"]) | set(proxies): from_settings = settings.value("network/" + scheme + "-proxy", "", type=str) from_default = default_proxies.get(scheme, "") env_scheme = scheme + '_proxy' if from_settings: os.environ[env_scheme] = from_settings elif from_default: os.environ[env_scheme] = from_default # crucial for windows/macos support else: os.environ.pop(env_scheme, "")
def save_plot(data, file_formats, filename=""): _LAST_DIR_KEY = "directories/last_graph_directory" _LAST_FILTER_KEY = "directories/last_graph_filter" settings = QSettings() start_dir = settings.value(_LAST_DIR_KEY, filename) if not start_dir or \ (not os.path.exists(start_dir) and not os.path.exists(os.path.split(start_dir)[0])): start_dir = os.path.expanduser("~") last_filter = settings.value(_LAST_FILTER_KEY, "") filename, writer, filter = \ filedialogs.get_file_name(start_dir, last_filter, file_formats) if not filename: return try: writer.write(filename, data) except Exception as e: QMessageBox.critical( None, "Error", 'Error occurred while saving file "{}": {}'.format(filename, e)) else: settings.setValue(_LAST_DIR_KEY, os.path.split(filename)[0]) settings.setValue(_LAST_FILTER_KEY, filter)
def check_for_updates(): settings = QSettings() check_updates = settings.value('startup/check-updates', True, type=bool) last_check_time = settings.value('startup/last-update-check-time', 0, type=int) ONE_DAY = 86400 if check_updates and time.time() - last_check_time > ONE_DAY: settings.setValue('startup/last-update-check-time', int(time.time())) from Orange.version import version as current class GetLatestVersion(QThread): resultReady = pyqtSignal(str) def run(self): try: request = Request('https://orange.biolab.si/version/', headers={ 'Accept': 'text/plain', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'User-Agent': self.ua_string()}) contents = urlopen(request, timeout=10).read().decode() # Nothing that this fails with should make Orange crash except Exception: # pylint: disable=broad-except log.exception('Failed to check for updates') else: self.resultReady.emit(contents) @staticmethod def ua_string(): is_anaconda = 'Continuum' in sys.version or 'conda' in sys.version return 'Orange{orange_version}:Python{py_version}:{platform}:{conda}'.format( orange_version=current, py_version='.'.join(sys.version[:3]), platform=sys.platform, conda='Anaconda' if is_anaconda else '', ) def compare_versions(latest): version = pkg_resources.parse_version if version(latest) <= version(current): return question = QMessageBox( QMessageBox.Information, 'Orange Update Available', 'A newer version of Orange is available.<br><br>' '<b>Current version:</b> {}<br>' '<b>Latest version:</b> {}'.format(current, latest), textFormat=Qt.RichText) ok = question.addButton('Download Now', question.AcceptRole) question.setDefaultButton(ok) question.addButton('Remind Later', question.RejectRole) question.finished.connect( lambda: question.clickedButton() == ok and QDesktopServices.openUrl(QUrl("https://orange.biolab.si/download/"))) question.show() thread = GetLatestVersion() thread.resultReady.connect(compare_versions) thread.start() return thread
def test_settings(self): spec = [config_slot("foo", bool, True, "foo doc"), config_slot("bar", int, 0, "bar doc"), ] store = QSettings(QSettings.IniFormat, QSettings.UserScope, "biolab.si", "Orange Canvas Unit Tests") store.clear() settings = Settings(defaults=spec, store=store) self.assertEqual(settings["foo"], True) self.assertEqual(settings.get("foo"), True) self.assertEqual(settings.get("bar", 3), 0, "Defaults") self.assertEqual(settings.get("bar"), settings["bar"]) self.assertEqual(settings.get("does not exist", "^&"), "^&", "get with default") self.assertIs(settings.get("does not exist"), None) with self.assertRaises(KeyError): settings["does not exist"] self.assertTrue(settings.isdefault("foo")) changed = [] settings.valueChanged.connect( lambda key, value: changed.append((key, value)) ) settings["foo"] = False self.assertEqual(changed[-1], ("foo", False), "valueChanged signal") self.assertEqual(len(changed), 1) self.assertEqual(settings["foo"], False, "updated value") self.assertEqual(settings.get("foo"), False) self.assertFalse(settings.isdefault("foo")) settings["bar"] = 1 self.assertEqual(changed[-1], ("bar", 1), "valueChanged signal") self.assertEqual(len(changed), 2) self.assertEqual(settings["bar"], 1) self.assertFalse(settings.isdefault("bar")) del settings["bar"] self.assertEqual(settings["bar"], 0) self.assertEqual(changed[-1], ("bar", 0)) # Only str or unicode can be keys with self.assertRaises(TypeError): settings[1] = 3 # value type check with self.assertRaises(TypeError): settings["foo"] = [] self.assertEqual(len(changed), 3) settings.add_default_slot(config_slot("foobar/foo", object, None, "")) group = settings.group("foobar") self.assertIs(group["foo"], None) group["foo"] = 3 self.assertEqual(changed[-1], ("foobar/foo", 3)) group["foonew"] = 5 self.assertIn("foobar/foonew", settings) settings["newkey"] = "newkeyvalue" self.assertIn("newkey", settings) group1 = group.group("bar") group1["barval"] = "barval" self.assertIn("foobar/bar/barval", settings) settings["foobar/bar/barval"] = 5 self.assertEqual(changed[-1], ("foobar/bar/barval", 5)) settings.clear() self.assertSetEqual(set(settings.keys()), set(["foo", "bar", "foobar/foo"]))
def setUp(self): self.file = tempfile.NamedTemporaryFile() self.filename = self.file.name self.settings = QSettings(self.filename, QSettings.IniFormat)
def main(argv=None): if argv is None: argv = sys.argv usage = "usage: %prog [options] [workflow_file]" parser = optparse.OptionParser(usage=usage) parser.add_option("--no-discovery", action="store_true", help="Don't run widget discovery " "(use full cache instead)") parser.add_option("--force-discovery", action="store_true", help="Force full widget discovery " "(invalidate cache)") parser.add_option("--clear-widget-settings", action="store_true", help="Remove stored widget setting") parser.add_option("--no-welcome", action="store_true", help="Don't show welcome dialog.") parser.add_option("--no-splash", action="store_true", help="Don't show splash screen.") parser.add_option("-l", "--log-level", help="Logging level (0, 1, 2, 3, 4)", type="int", default=1) parser.add_option("--style", help="QStyle to use", type="str", default=None) parser.add_option("--stylesheet", help="Application level CSS style sheet to use", type="str", default=None) parser.add_option("--qt", help="Additional arguments for QApplication", type="str", default=None) (options, args) = parser.parse_args(argv[1:]) levels = [logging.CRITICAL, logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] # Fix streams before configuring logging (otherwise it will store # and write to the old file descriptors) fix_win_pythonw_std_stream() # Try to fix fonts on OSX Mavericks fix_osx_10_9_private_font() # File handler should always be at least INFO level so we need # the application root level to be at least at INFO. root_level = min(levels[options.log_level], logging.INFO) rootlogger = logging.getLogger(canvas.__name__) rootlogger.setLevel(root_level) # Initialize SQL query and execution time logger (in SqlTable) sql_level = min(levels[options.log_level], logging.INFO) make_sql_logger(sql_level) # Standard output stream handler at the requested level stream_hander = logging.StreamHandler() stream_hander.setLevel(level=levels[options.log_level]) rootlogger.addHandler(stream_hander) log.info("Starting 'Orange Canvas' application.") qt_argv = argv[:1] style = options.style defaultstylesheet = "orange.qss" fusiontheme = None if style is not None: if style.startswith("fusion:"): qt_argv += ["-style", "fusion"] _, _, fusiontheme = style.partition(":") else: qt_argv += ["-style", style] if options.qt is not None: qt_argv += shlex.split(options.qt) qt_argv += args if QT_VERSION >= 0x50600: CanvasApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) log.debug("Starting CanvasApplicaiton with argv = %r.", qt_argv) app = CanvasApplication(qt_argv) if app.style().metaObject().className() == "QFusionStyle": if fusiontheme == "breeze-dark": app.setPalette(breeze_dark()) defaultstylesheet = "darkorange.qss" palette = app.palette() if style is None and palette.color(QPalette.Window).value() < 127: log.info("Switching default stylesheet to darkorange") defaultstylesheet = "darkorange.qss" # NOTE: config.init() must be called after the QApplication constructor config.init() clear_settings_flag = os.path.join( config.widget_settings_dir(), "DELETE_ON_START") if options.clear_widget_settings or \ os.path.isfile(clear_settings_flag): log.info("Clearing widget settings") shutil.rmtree( config.widget_settings_dir(), ignore_errors=True) # Set http_proxy environment variables, after (potentially) clearing settings fix_set_proxy_env() file_handler = logging.FileHandler( filename=os.path.join(config.log_dir(), "canvas.log"), mode="w" ) file_handler.setLevel(root_level) rootlogger.addHandler(file_handler) # intercept any QFileOpenEvent requests until the main window is # fully initialized. # NOTE: The QApplication must have the executable ($0) and filename # arguments passed in argv otherwise the FileOpen events are # triggered for them (this is done by Cocoa, but QApplicaiton filters # them out if passed in argv) open_requests = [] def onrequest(url): log.info("Received an file open request %s", url) open_requests.append(url) app.fileOpenRequest.connect(onrequest) settings = QSettings() stylesheet = options.stylesheet or defaultstylesheet stylesheet_string = None if stylesheet != "none": if os.path.isfile(stylesheet): with open(stylesheet, "r") as f: stylesheet_string = f.read() else: if not os.path.splitext(stylesheet)[1]: # no extension stylesheet = os.path.extsep.join([stylesheet, "qss"]) pkg_name = canvas.__name__ resource = "styles/" + stylesheet if pkg_resources.resource_exists(pkg_name, resource): stylesheet_string = \ pkg_resources.resource_string(pkg_name, resource).decode() base = pkg_resources.resource_filename(pkg_name, "styles") pattern = re.compile( r"^\s@([a-zA-Z0-9_]+?)\s*:\s*([a-zA-Z0-9_/]+?);\s*$", flags=re.MULTILINE ) matches = pattern.findall(stylesheet_string) for prefix, search_path in matches: QDir.addSearchPath(prefix, os.path.join(base, search_path)) log.info("Adding search path %r for prefix, %r", search_path, prefix) stylesheet_string = pattern.sub("", stylesheet_string) else: log.info("%r style sheet not found.", stylesheet) # Add the default canvas_icons search path dirpath = os.path.abspath(os.path.dirname(canvas.__file__)) QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons")) canvas_window = CanvasMainWindow() canvas_window.setWindowIcon(config.application_icon()) if stylesheet_string is not None: canvas_window.setStyleSheet(stylesheet_string) if not options.force_discovery: reg_cache = cache.registry_cache() else: reg_cache = None widget_discovery = qt.QtWidgetDiscovery(cached_descriptions=reg_cache) widget_registry = qt.QtWidgetRegistry() widget_discovery.found_category.connect( widget_registry.register_category ) widget_discovery.found_widget.connect( widget_registry.register_widget ) want_splash = \ settings.value("startup/show-splash-screen", True, type=bool) and \ not options.no_splash if want_splash: pm, rect = config.splash_screen() splash_screen = SplashScreen(pixmap=pm, textRect=rect) splash_screen.setFont(QFont("Helvetica", 12)) color = QColor("#FFD39F") def show_message(message): splash_screen.showMessage(message, color=color) widget_discovery.discovery_start.connect(splash_screen.show) widget_discovery.discovery_process.connect(show_message) widget_discovery.discovery_finished.connect(splash_screen.hide) log.info("Running widget discovery process.") cache_filename = os.path.join(cache_dir(), "widget-registry.pck") if options.no_discovery: with open(cache_filename, "rb") as f: widget_registry = pickle.load(f) widget_registry = qt.QtWidgetRegistry(widget_registry) else: widget_discovery.run(config.widgets_entry_points()) # Store cached descriptions cache.save_registry_cache(widget_discovery.cached_descriptions) with open(cache_filename, "wb") as f: pickle.dump(WidgetRegistry(widget_registry), f) set_global_registry(widget_registry) canvas_window.set_widget_registry(widget_registry) canvas_window.show() canvas_window.raise_() want_welcome = \ settings.value("startup/show-welcome-screen", True, type=bool) \ and not options.no_welcome # Process events to make sure the canvas_window layout has # a chance to activate (the welcome dialog is modal and will # block the event queue, plus we need a chance to receive open file # signals when running without a splash screen) app.processEvents() app.fileOpenRequest.connect(canvas_window.open_scheme_file) if want_welcome and not args and not open_requests: canvas_window.welcome_dialog() elif args: log.info("Loading a scheme from the command line argument %r", args[0]) canvas_window.load_scheme(args[0]) elif open_requests: log.info("Loading a scheme from an `QFileOpenEvent` for %r", open_requests[-1]) canvas_window.load_scheme(open_requests[-1].toLocalFile()) # local references prevent destruction _ = show_survey() __ = check_for_updates() # Tee stdout and stderr into Output dock log_view = canvas_window.log_view() stdout = TextStream() stdout.stream.connect(log_view.write) if sys.stdout: stdout.stream.connect(sys.stdout.write) stdout.flushed.connect(sys.stdout.flush) stderr = TextStream() error_writer = log_view.formated(color=Qt.red) stderr.stream.connect(error_writer.write) if sys.stderr: stderr.stream.connect(sys.stderr.write) stderr.flushed.connect(sys.stderr.flush) log.info("Entering main event loop.") try: with patch('sys.excepthook', ExceptHook(stream=stderr, canvas=canvas_window, handledException=handle_exception)),\ patch('sys.stderr', stderr),\ patch('sys.stdout', stdout): status = app.exec_() except BaseException: log.error("Error in main event loop.", exc_info=True) canvas_window.deleteLater() app.processEvents() app.flush() del canvas_window # Collect any cycles before deleting the QApplication instance gc.collect() del app return status
def __init__(self, data): icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxWarning) F = self.DataField def _finished(*, key=(data.get(F.MODULE), data.get(F.WIDGET_MODULE)), filename=data.get(F.WIDGET_SCHEME)): self._cache.add(key) try: os.remove(filename) except Exception: pass super().__init__(None, Qt.Window, modal=True, sizeGripEnabled=True, windowIcon=icon, windowTitle='Unexpected Error', finished=_finished) self._data = data layout = QVBoxLayout(self) self.setLayout(layout) labels = QWidget(self) labels_layout = QHBoxLayout(self) labels.setLayout(labels_layout) labels_layout.addWidget(QLabel(pixmap=icon.pixmap(50, 50))) labels_layout.addWidget(QLabel( 'The program encountered an unexpected error. Please<br>' 'report it anonymously to the developers.<br><br>' 'The following data will be reported:')) labels_layout.addStretch(1) layout.addWidget(labels) font = QFont('Monospace', 10) font.setStyleHint(QFont.Monospace) font.setFixedPitch(True) textbrowser = QTextBrowser(self, font=font, openLinks=False, lineWrapMode=QTextBrowser.NoWrap, anchorClicked=QDesktopServices.openUrl) layout.addWidget(textbrowser) def _reload_text(): add_scheme = cb.isChecked() settings.setValue('error-reporting/add-scheme', add_scheme) lines = ['<table>'] for k, v in data.items(): if k.startswith('_'): continue _v, v = v, escape(str(v)) if k == F.WIDGET_SCHEME: if not add_scheme: continue v = '<a href="{}">{}</a>'.format(urljoin('file:', pathname2url(_v)), v) if k in (F.STACK_TRACE, F.LOCALS): v = v.replace('\n', '<br>').replace(' ', ' ') lines.append('<tr><th align="left">{}:</th><td>{}</td></tr>'.format(k, v)) lines.append('</table>') textbrowser.setHtml(''.join(lines)) settings = QSettings() cb = QCheckBox( 'Include workflow (data will NOT be transmitted)', self, checked=settings.value('error-reporting/add-scheme', True, type=bool)) cb.stateChanged.connect(_reload_text) _reload_text() layout.addWidget(cb) buttons = QWidget(self) buttons_layout = QHBoxLayout(self) buttons.setLayout(buttons_layout) buttons_layout.addWidget( QPushButton('Send Report (Thanks!)', default=True, clicked=self.accept)) buttons_layout.addWidget(QPushButton("Don't Send", default=False, clicked=self.reject)) layout.addWidget(buttons)
def _userconfirmed(): session_hist = QSettings(filename, QSettings.IniFormat) session_hist.beginGroup(namespace) session_hist.setValue( "{}/confirmed".format(message.persistent_id), True) session_hist.sync()