Skip to content
This repository has been archived by the owner on Nov 9, 2021. It is now read-only.

Pep484 new #75

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
exclude = help/,venv/,resources.py
per-file-ignores = stac_browser.py:F401,F403
max-line-length = 119

[mypy]
files=best_practices,test
disallow_untyped_calls=True
disallow_untyped_defs=True
check_untyped_defs=True
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,4 @@ $RECYCLE.BIN/
*.lnk

# End of https://www.gitignore.io/api/osx,linux,python,windows
.vscode/settings.json
1 change: 1 addition & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"apis": [{"id": "default-staccato", "href": "https://stac.boundlessgeo.io", "data": {}, "collections": []}, {"id": "default-sat-api", "href": "https://sat-api.developmentseed.org", "data": {}, "collections": []}, {"id": "default-astraea", "href": "https://eod-catalog-svc-prod.astraea.earth/api/v2/stac/search", "data": {}, "collections": []}], "download_directory": "/home/suricactus", "last_update": 1574216729.4010117, "api_update_interval": 86400}
26 changes: 15 additions & 11 deletions controllers/about_dialog.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
from PyQt5 import uic, QtWidgets
from typing import Any
from PyQt5 import uic
from PyQt5.QtWidgets import (QDialog, QWidget)

from ..utils import ui
from stac_browser.utils import ui


FORM_CLASS: Any
FORM_CLASS, _ = uic.loadUiType(ui.path('about_dialog.ui'))


class AboutDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, path=None, parent=None, iface=None):
class AboutDialog(QDialog, FORM_CLASS):
def __init__(self, path: str, parent: QWidget = None) -> None:
assert isinstance(path, str), 'provided path must be a string'

super(AboutDialog, self).__init__(parent)
self.iface = iface

self.setupUi(self)

if path is not None:
with open(path, 'r') as f:
contents = f.read()
self.textBrowser.setHtml(contents)
with open(path, 'r') as f:
contents = f.read()

self.textBrowser.setHtml(contents)

self.closeButton.clicked.connect(self.on_close_clicked)
self.closeButton.clicked.connect(self._onCloseClicked)

def on_close_clicked(self):
def _onCloseClicked(self) -> None:
self.reject()
80 changes: 43 additions & 37 deletions controllers/add_edit_api_dialog.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,99 @@
from typing import Any

import uuid
import urllib
from urllib.error import URLError

from PyQt5 import uic, QtWidgets
from PyQt5 import uic
from PyQt5.QtWidgets import (QDialog, QWidget)

from ..utils import ui
from ..utils.logging import error
from qgis.utils import iface

from ..threads.load_api_data_thread import LoadAPIDataThread
from ..models.api import API
from stac_browser.utils import ui
from stac_browser.utils.logging import error
from stac_browser.utils.types import (DataT, HooksT)
from stac_browser.threads.load_api_data_thread import LoadAPIDataThread
from stac_browser.models.api import API

FORM_CLASS: Any
FORM_CLASS, _ = uic.loadUiType(ui.path('add_edit_api_dialog.ui'))


class AddEditAPIDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, data={}, hooks={}, parent=None, iface=None):
class AddEditAPIDialog(QDialog, FORM_CLASS):
def __init__(self, data: DataT = {}, hooks: HooksT = {}, parent: QWidget = None) -> None:
super(AddEditAPIDialog, self).__init__(parent)

self.data = data
self.hooks = hooks
self.iface = iface

self.setupUi(self)

self.populate_details()
self.populate_auth_method_combo()
self._populateDetails()
self._populateAuthMethodCombo()

self.cancelButton.clicked.connect(self.on_cancel_clicked)
self.removeButton.clicked.connect(self.on_remove_clicked)
self.saveAddButton.clicked.connect(self.on_save_add_clicked)
self.cancelButton.clicked.connect(self._onCancelClicked)
self.removeButton.clicked.connect(self._onRemoveClicked)
self.saveAddButton.clicked.connect(self._onSaveAddClicked)

def on_cancel_clicked(self):
def _onCancelClicked(self) -> None:
self.reject()

def on_remove_clicked(self):
def _onRemoveClicked(self) -> None:
self.hooks['remove_api'](self.api)
self.accept()

def set_all_enabled(self, enabled):
self.urlEditBox.setEnabled(enabled)
self.authenticationCombo.setEnabled(enabled)
self.removeButton.setEnabled(enabled)
self.cancelButton.setEnabled(enabled)
self.saveAddButton.setEnabled(enabled)
def _setAllEnabled(self, is_enabled: bool) -> None:
self.urlEditBox.setEnabled(is_enabled)
self.authenticationCombo.setEnabled(is_enabled)
self.removeButton.setEnabled(is_enabled)
self.cancelButton.setEnabled(is_enabled)
self.saveAddButton.setEnabled(is_enabled)

def on_save_add_clicked(self):
self.set_all_enabled(False)
def _onSaveAddClicked(self) -> None:
self._setAllEnabled(False)
self.saveAddButton.setText('Testing Connection...')

api_id = str(uuid.uuid4())

if self.api is not None:
api_id = self.api.id

api = API({'id': api_id, 'href': self.urlEditBox.text()})
self.loading_thread = LoadAPIDataThread(
api,
on_error=self.on_api_error,
on_finished=self.on_api_success)

self.loading_thread = LoadAPIDataThread(api)
self.loading_thread.error.connect(self._onApiError)
self.loading_thread.success.connect(self._onApiSuccess)
self.loading_thread.start()

def on_api_error(self, e):
self.set_all_enabled(True)
def _onApiError(self, err: Exception) -> None:
self._setAllEnabled(True)
if self.api is None:
self.saveAddButton.setText('Add')
else:
self.saveAddButton.setText('Save')

if type(e) == urllib.error.URLError:
error(self.iface, f'Connection Failed; {e.reason}')
if type(err) == URLError:
error(iface, f'Connection Failed; {err.reason}')
else:
error(self.iface, f'Connection Failed; {type(e).__name__}')
error(iface, f'Connection Failed; {type(err).__name__}')

def on_api_success(self, api):
def _onApiSuccess(self, api: API) -> None:
if self.api is None:
self.hooks['add_api'](api)
else:
self.hooks['edit_api'](api)
self.accept()

@property
def api(self):
def api(self) -> API:
return self.data.get('api', None)

def populate_details(self):
def _populateDetails(self) -> None:
if self.api is None:
self.saveAddButton.setText('Add')
self.removeButton.hide()
return

self.urlEditBox.setText(self.api.href)

def populate_auth_method_combo(self):
def _populateAuthMethodCombo(self) -> None:
self.authenticationCombo.addItem('No Auth')
55 changes: 32 additions & 23 deletions controllers/collection_loading_dialog.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,56 @@
from typing import (Dict, Any, List, Callable)

import time
import urllib
import urllib.error

from PyQt5 import uic
from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import (QDialog, QWidget)

from PyQt5 import uic, QtWidgets
from qgis.gui import QgisInterface
from qgis.utils import iface

from ..utils.config import Config
from ..utils.logging import error
from ..utils import ui
from ..threads.load_collections_thread import LoadCollectionsThread
from stac_browser.utils import ui
from stac_browser.utils.config import Config
from stac_browser.utils.logging import error
from stac_browser.utils.types import (DataT, HooksT)
from stac_browser.threads.load_collections_thread import LoadCollectionsThread
from stac_browser.models.api import API


FORM_CLASS: Any
FORM_CLASS, _ = uic.loadUiType(ui.path('collection_loading_dialog.ui'))


class CollectionLoadingDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, data={}, hooks={}, parent=None, iface=None):
class CollectionLoadingDialog(QDialog, FORM_CLASS):
def __init__(self, data: DataT = {}, hooks: HooksT = {}, parent: QWidget = None) -> None:
super(CollectionLoadingDialog, self).__init__(parent)

self.data = data
self.hooks = hooks
self.iface = iface

self.setupUi(self)
self.setFixedSize(self.size())

self.loading_thread = LoadCollectionsThread(
Config().apis,
on_progress=self.on_progress_update,
on_error=self.on_error,
on_finished=self.on_loading_finished)
self.loadingThread = LoadCollectionsThread(Config().apis)

self.loadingThread.progress.connect(self._onProgressUpdate)
self.loadingThread.error.connect(self._onError)
self.loadingThread.finished.connect(self._onLoadingFinished)

self.loading_thread.start()
self.loadingThread.start()

def on_progress_update(self, progress, api):
def _onProgressUpdate(self, progress: float, api: API) -> None:
self.label.setText(f'Loading {api}')
self.progressBar.setValue(int(progress * 100))

def on_error(self, e, api):
if type(e) == urllib.error.URLError:
error(self.iface, f'Failed to load {api.href}; {e.reason}')
def _onError(self, err: Exception, api: API) -> None:
if type(err) == urllib.error.URLError:
error(iface, f'Failed to load {api.href}; {err.reason}')
else:
error(self.iface, f'Failed to load {api.href}; {type(e).__name__}')
error(iface, f'Failed to load {api.href}; {type(err).__name__}')

def on_loading_finished(self, apis):
def _onLoadingFinished(self, apis: List[API]) -> None:
config = Config()
config.apis = apis
config.last_update = time.time()
Expand All @@ -50,7 +59,7 @@ def on_loading_finished(self, apis):
self.progressBar.setValue(100)
self.hooks['on_finished'](apis)

def closeEvent(self, event):
def closeEvent(self, event: QEvent) -> None:
if event.spontaneous():
self.loading_thread.terminate()
self.loadingThread.terminate()
self.hooks['on_close']()
Loading