diff --git a/src/__main__.py b/src/__main__.py index 285039f..97ec321 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -2,101 +2,18 @@ This is the main module. It basically checks that there is a hapi api key, asks for one if there is not one, and launches the main GUI. Thats about it. """ -import os -import sys from multiprocessing import freeze_support +import sys -from PyQt5 import QtCore, QtWidgets - -from metadata.config import Config # This should be imported first: it verifies the correct python version is running, and moves the # current working directory to wherever it ought to be. Importing things for their side-effects # is probably bad practice, but so is using python. -from startup import verify_internet_connection_and_obtain_api_key -from utils.log import TextReceiver -from windows.main_window import MainWindow -from worker.hapi_thread import HapiThread -from worker.hapi_worker import HapiWorker -from worker.work_request import WorkRequest - - -# Create the data folder if it doesn't exist. -if not os.path.exists(Config.data_folder): - os.makedirs(Config.data_folder) - - -# This is not necessary right now but will be helpful of the behavior of -# the QApplication needs to be modified. -# class App(QtWidgets.QApplication): -# def __init__(self, *args): -# QtWidgets.QApplication.__init__(self, *args) - -def main(): - """ - The main method starts the GUI after asking for an api key if necessary. - """ - if len(sys.argv) > 1 and sys.argv[1] == 'test': - import test - - test.run_tests() - return 0 - - if Config.high_dpi: - # Enable High DPI display with PyQt5 - QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) - - # Fix for mac-based systems... - os.environ['no_proxy'] = '*' - - ## - # The following blocks of code verify the hapi API key is in place, and it - # is valid. If it is not valid or in place the user will we prompted for - # one. This code also checks for a working internet connection, as hapi - # needs one to download data. In the future, if there is no internet - # connection the GUI should simply disable the features that require it, - # and there could be a periodic check for internet connection that will - # re-enable them. - - if not verify_internet_connection_and_obtain_api_key(): - return 0 - - from metadata.molecule_meta import MoleculeMeta - - WorkRequest.start_work_process() - - # Hapi is now started automatically in the work process - # start = HapiWorker(WorkRequest.START_HAPI, {}) - # start.start() # When a start_hapi request is sent, it starts automatically. - - _ = MoleculeMeta(0) - from metadata.xsc_meta import CrossSectionMeta - - # If the cache is expired, download a list of the cross section meta file. - # This also populates the CrossSectionMeta.molecule_metas field. - _ = CrossSectionMeta(0) - - app = QtWidgets.QApplication(sys.argv) - - window = MainWindow() - window.gui.adjustSize() - - TextReceiver.init(window) - - _qt_result = app.exec_() - - TextReceiver.redirect_close() - close = HapiWorker(WorkRequest.END_WORK_PROCESS, { }, callback = None) - close.safe_exit() - WorkRequest.WORKER.process.join() - HapiThread.kill_all() - sys.exit(0) - return 0 +from startup import fix_cwd, check_version +from app import run +check_version() +fix_cwd() if __name__ == '__main__': freeze_support() - # try: - # main() - # except Exception as error: - # debug(error) - main() + sys.exit(run()) diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..ec3f34d --- /dev/null +++ b/src/app.py @@ -0,0 +1,141 @@ +""" +This module launches the main GUI, which should only be ran after all setup is finished +""" + +import os +import sys +from urllib.error import HTTPError, URLError + +from PyQt5 import QtCore, QtWidgets + +from utils.log import TextReceiver +from windows.main_window import MainWindow +from worker.hapi_thread import HapiThread +from worker.hapi_worker import HapiWorker +from worker.work_request import WorkRequest +from metadata.config import Config + + +def obtain_apikey(): + """ + Attempts to obtain an API key from the user if there is not one in the user Config already. + If there is no valid API key when this function is called, the user will be prompted for one + and the program will exit. + """ + Config.hapi_api_key = Config.hapi_api_key.strip().lower() + + from widgets.apikey_help_widget import ApiKeyHelpWidget, ApiKeyValidator + + if Config.hapi_api_key == '0000' or \ + ApiKeyValidator.APIKEY_REGEX.match(Config.hapi_api_key) is None: + app = QtWidgets.QApplication(sys.argv) + _ = ApiKeyHelpWidget() + app.exec_() + + +def verify_internet_connection_and_obtain_api_key(): + """ + This function also verifies that the supplied hapi api key is valid. If the api key is not + valid, then the value in the config (in memory and on disk) is overwritten and the + obtain_apikey function is called, which will prompt the user for a valid API key and close the + program. + :return: True if there is an internet connection, false otherwise. + """ + import urllib.request + from utils.hapi_api import CrossSectionApi + + try: + with urllib.request.urlopen( + f"{CrossSectionApi.BASE_URL}/{CrossSectionApi.API_ROUTE}/{Config.hapi_api_key}" \ + f"{CrossSectionApi.XSC_META_ROUTE}"): + pass + return True + except HTTPError as _: + # An HTTP error code was given the response. This means the APIKEY was invalid + err_msg = """ +Your HAPI API key is invalid, or you did not enter one. Hapiest will close after you hit Ok, and +will prompt you for your hapi API key upon the next launch. If you think your HAPI is valid, +please file a bug report at https://github.com/hitranonline/hapiest +""" + Config.hapi_api_key = '0000' + obtain_apikey() + Config.rewrite_config() + except URLError as _: + # URL Lookup failed. Probably means there is no internet connection + err_msg = """ +You do not have a working internet connection. A working internet connection +is needed in order to use hapiest. +""" + + from widgets.error_msg_widget import ErrorMsgWidget + + app = QtWidgets.QApplication(sys.argv) + _ = ErrorMsgWidget(err_msg) + app.exec_() + sys.exit(0) + + +def run(): + """ + The main method starts the GUI after asking for an api key if necessary. + """ + + # Create the data folder if it doesn't exist. + if not os.path.exists(Config.data_folder): + os.makedirs(Config.data_folder) + + if len(sys.argv) > 1 and sys.argv[1] == 'test': + import test + + test.run_tests() + return 0 + + if Config.high_dpi: + # Enable High DPI display with PyQt5 + QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) + + # Fix for mac-based systems... + os.environ['no_proxy'] = '*' + + ## + # The following blocks of code verify the hapi API key is in place, and it + # is valid. If it is not valid or in place the user will we prompted for + # one. This code also checks for a working internet connection, as hapi + # needs one to download data. In the future, if there is no internet + # connection the GUI should simply disable the features that require it, + # and there could be a periodic check for internet connection that will + # re-enable them. + + if not verify_internet_connection_and_obtain_api_key(): + return 0 + + from metadata.molecule_meta import MoleculeMeta + + WorkRequest.start_work_process() + + # Hapi is now started automatically in the work process + # start = HapiWorker(WorkRequest.START_HAPI, {}) + # start.start() # When a start_hapi request is sent, it starts automatically. + + _ = MoleculeMeta(0) + from metadata.xsc_meta import CrossSectionMeta + + # If the cache is expired, download a list of the cross section meta file. + # This also populates the CrossSectionMeta.molecule_metas field. + _ = CrossSectionMeta(0) + + app = QtWidgets.QApplication(sys.argv) + + window = MainWindow() + window.gui.adjustSize() + + TextReceiver.init(window) + + _qt_result = app.exec_() + + TextReceiver.redirect_close() + close = HapiWorker(WorkRequest.END_WORK_PROCESS, {}, callback=None) + close.safe_exit() + WorkRequest.WORKER.process.join() + HapiThread.kill_all() + return 0 diff --git a/src/startup.py b/src/startup.py index 7d3a68e..49c2c00 100644 --- a/src/startup.py +++ b/src/startup.py @@ -1,83 +1,28 @@ """ -This is the startup module. It has the utility function -verify_internet_connection_and_obtain_api_key. When this package is imported, it moves the -current working directory to the proper place, if necessary. +This is the startup module. All of the functions here should be ran before the main app +is started. """ import os import re import sys -from urllib.error import HTTPError, URLError -from PyQt5 import QtWidgets - -if sys.version_info < (3, 6): - print(f"You must have Python 3 installed to use hapiest, current version is {str(sys.version)}") - sys.exit(0) - -# If someone launches the program through the command 'python3 __main__.py' -# this moves the current working directory to the proper place -SRC_REGEX = re.compile('.+src\\Z') -if SRC_REGEX.match(os.getcwd()): - os.chdir('..') - -from metadata.config import Config - - -def obtain_apikey(): +def check_version(): """ - Attempts to obtain an API key from the user if there is not one in the user Config already. - If there is no valid API key when this function is called, the user will be prompted for one - and the program will exit. + Ensures the version is at least python 3.6. The program exits if the wrong version of + python is used. """ - Config.hapi_api_key = Config.hapi_api_key.strip().lower() - - from widgets.apikey_help_widget import ApiKeyHelpWidget, ApiKeyValidator + if sys.version_info < (3, 6): + print(f"You must have Python 3 installed to use hapiest, current version is" + f"{str(sys.version)}") + sys.exit(0) - if Config.hapi_api_key == '0000' or \ - ApiKeyValidator.APIKEY_REGEX.match(Config.hapi_api_key) is None: - app = QtWidgets.QApplication(sys.argv) - _ = ApiKeyHelpWidget() - app.exec_() - -def verify_internet_connection_and_obtain_api_key(): +def fix_cwd(): """ - This function also verifies that the supplied hapi api key is valid. If the api key is not - valid, then the value in the config (in memory and on disk) is overwritten and the - obtain_apikey function is called, which will prompt the user for a valid API key and close the - program. - :return: True if there is an internet connection, false otherwise. + If someone launches the program through the command 'python3 __main__.py', the current working + directory is in the wrong place. This moves it to where it should be. """ - import urllib.request - from utils.hapi_api import CrossSectionApi - - try: - with urllib.request.urlopen( - f"{CrossSectionApi.BASE_URL}/{CrossSectionApi.API_ROUTE}/{Config.hapi_api_key}" \ - f"{CrossSectionApi.XSC_META_ROUTE}"): - pass - return True - except HTTPError as _: - # An HTTP error code was given the response. This means the APIKEY was invalid - err_msg = """ -Your HAPI API key is invalid, or you did not enter one. Hapiest will close after you hit Ok, and -will prompt you for your hapi API key upon the next launch. If you think your HAPI is valid, -please file a bug report at https://github.com/hitranonline/hapiest -""" - Config.hapi_api_key = '0000' - obtain_apikey() - Config.rewrite_config() - except URLError as _: - # URL Lookup failed. Probably means there is no internet connection - err_msg = """ -You do not have a working internet connection. A working internet connection -is needed in order to use hapiest. -""" - - from widgets.error_msg_widget import ErrorMsgWidget - - app = QtWidgets.QApplication(sys.argv) - _ = ErrorMsgWidget(err_msg) - app.exec_() - sys.exit(0) + src_regex = re.compile('.+src\\Z') + if src_regex.match(os.getcwd()): + os.chdir('..')