From 03c47f9150f2fd7fccd6c232dd86654ec7614839 Mon Sep 17 00:00:00 2001 From: pveigadecamargo Date: Thu, 1 Aug 2024 14:17:10 +1000 Subject: [PATCH 1/7] fixes messaging --- aequilibrae/utils/signal.py | 2 +- tests/aequilibrae/project/test_osm_downloader.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/aequilibrae/utils/signal.py b/aequilibrae/utils/signal.py index 7e5b19964..a5a467030 100644 --- a/aequilibrae/utils/signal.py +++ b/aequilibrae/utils/signal.py @@ -5,7 +5,7 @@ def noop(_): pass -if iutil.find_spec("PyQt5") is not None: +if iutil.find_spec("qgis") is not None: from PyQt5.QtCore import pyqtSignal as SIGNAL # type: ignore noop(SIGNAL.__class__) # This should be no-op but it stops PyCharm from "optimising" the above import diff --git a/tests/aequilibrae/project/test_osm_downloader.py b/tests/aequilibrae/project/test_osm_downloader.py index 7c5fe3bb7..e0d0289b0 100644 --- a/tests/aequilibrae/project/test_osm_downloader.py +++ b/tests/aequilibrae/project/test_osm_downloader.py @@ -1,4 +1,3 @@ -import importlib.util as iutil import os from random import random from tempfile import gettempdir @@ -8,9 +7,6 @@ from aequilibrae.project.network.osm.osm_downloader import OSMDownloader -spec = iutil.find_spec("PyQt5") -pyqt = spec is not None - class TestOSMDownloader(TestCase): def setUp(self) -> None: From 0564da7d9504bc62a14dc8682ef106cd20f0dffe Mon Sep 17 00:00:00 2001 From: pveigadecamargo Date: Thu, 1 Aug 2024 14:54:32 +1000 Subject: [PATCH 2/7] fixes messaging --- aequilibrae/utils/signal.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/aequilibrae/utils/signal.py b/aequilibrae/utils/signal.py index a5a467030..d68729dff 100644 --- a/aequilibrae/utils/signal.py +++ b/aequilibrae/utils/signal.py @@ -6,7 +6,14 @@ def noop(_): if iutil.find_spec("qgis") is not None: - from PyQt5.QtCore import pyqtSignal as SIGNAL # type: ignore + from PyQt5.QtCore import QThread + from PyQt5.QtCore import pyqtSignal + + class SIGNAL(QThread): + signal = pyqtSignal(str) + + def emit(self, val): + self.signal.emit(val) noop(SIGNAL.__class__) # This should be no-op but it stops PyCharm from "optimising" the above import else: From ca69e3e209adc9a7467c321b824081739c389eeb Mon Sep 17 00:00:00 2001 From: pveigadecamargo Date: Thu, 8 Aug 2024 16:48:39 +1000 Subject: [PATCH 3/7] messaging --- aequilibrae/paths/all_or_nothing.py | 2 ++ aequilibrae/paths/linear_approximation.py | 12 ++++----- aequilibrae/utils/interface/__init__.py | 0 aequilibrae/utils/interface/worker_thread.py | 27 ++++++++++++++++++++ aequilibrae/utils/python_signal.py | 14 +++++++--- aequilibrae/utils/signal.py | 11 ++------ 6 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 aequilibrae/utils/interface/__init__.py create mode 100644 aequilibrae/utils/interface/worker_thread.py diff --git a/aequilibrae/paths/all_or_nothing.py b/aequilibrae/paths/all_or_nothing.py index 387b073e9..bbd4de3a9 100644 --- a/aequilibrae/paths/all_or_nothing.py +++ b/aequilibrae/paths/all_or_nothing.py @@ -46,6 +46,8 @@ def _build_signal(self): if self.assignment is None: self.assignment = SIGNAL(object) self.assignment.emit(["start", self.matrix.zones, self.class_name]) + else: + self.assignment.emit(["set_text", f"All-or-Nothing: {self.class_name}"]) def doWork(self): self.execute() diff --git a/aequilibrae/paths/linear_approximation.py b/aequilibrae/paths/linear_approximation.py index 3c7f56f39..7011d7690 100644 --- a/aequilibrae/paths/linear_approximation.py +++ b/aequilibrae/paths/linear_approximation.py @@ -20,16 +20,16 @@ from aequilibrae.paths.traffic_assignment import TrafficAssignment from aequilibrae.utils.signal import SIGNAL +from aequilibrae.utils.interface.worker_thread import WorkerThread from aequilibrae.utils.python_signal import PythonSignal -class LinearApproximation: +class LinearApproximation(WorkerThread): def __init__(self, assig_spec, algorithm, project=None) -> None: + WorkerThread.__init__(self, None) self.equilibration = SIGNAL(object) self.assignment = SIGNAL(object) - if isinstance(self.assignment, PythonSignal): - self.assignment.pos = 1 - + self.assignment.emit(["set_position", 1]) self.logger = project.logger if project else logging.getLogger("aequilibrae") self.project_path = project.project_base_path if project else gettempdir() @@ -471,6 +471,7 @@ def execute(self): # noqa: C901 self.equilibration.emit(["start", self.max_iter, "Equilibrium Assignment"]) self.logger.info(f"{self.algorithm} Assignment STATS") self.logger.info("Iteration, RelativeGap, stepsize") + self.assignment.emit(["start", c.matrix.zones, "All-or-Nothing"]) for self.iter in range(1, self.max_iter + 1): # noqa: B020 self.iteration_issue = [] self.equilibration.emit(["key_value", "rgap", self.rgap]) @@ -481,7 +482,6 @@ def execute(self): # noqa: C901 self.__maybe_create_path_file_directories() for c in self.traffic_classes: # type: TrafficClass - self.assignment.emit(["start", c.matrix.zones, "All-or-Nothing"]) # cost = c.fixed_cost / c.vot + self.congested_time # now only once cost = c.fixed_cost + self.congested_time aggregate_link_costs(cost, c.graph.compact_cost, c.results.crosswalk) @@ -513,7 +513,7 @@ def execute(self): # noqa: C901 copy_three_dimensions( c.results.select_link_od.matrix[name], # matrix being written into np.sum(self.aons[c._id].aux_res.temp_sl_od_matrix, axis=0)[ - idx, :, :, : + idx, :, :, : ], # results after the iteration self.cores, # core count ) diff --git a/aequilibrae/utils/interface/__init__.py b/aequilibrae/utils/interface/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aequilibrae/utils/interface/worker_thread.py b/aequilibrae/utils/interface/worker_thread.py new file mode 100644 index 000000000..6ef9af617 --- /dev/null +++ b/aequilibrae/utils/interface/worker_thread.py @@ -0,0 +1,27 @@ +from aequilibrae.utils.qgis_utils import inside_qgis + +if inside_qgis: + from PyQt5.QtCore import QThread + from PyQt5.QtCore import pyqtSignal +else: + class QThread: # type: ignore + def __init__(self, *arg): + pass + + +class WorkerThread(QThread): + if inside_qgis: + jobFinished = pyqtSignal(object) + + def __init__(self, parentThread): + QThread.__init__(self, parentThread) + + def run(self): + self.running = True + success = self.doWork() + if inside_qgis: + self.jobFinished.emit(success) + + def stop(self): + self.running = False + pass \ No newline at end of file diff --git a/aequilibrae/utils/python_signal.py b/aequilibrae/utils/python_signal.py index e0298ba1a..d8615451e 100644 --- a/aequilibrae/utils/python_signal.py +++ b/aequilibrae/utils/python_signal.py @@ -28,7 +28,7 @@ class PythonSignal: # type: ignore ['action', 'bar hierarchy', 'value', 'text', 'master'] 'action': 'start', 'update', or 'finished_*_processing' (the last one applies in QGIS) - 'bar hierarchy': 'master' or 'secondary' + 'position': Position (0 for top, 1 for bottom) 'value': Numerical value for the action (total or current) 'text': Whatever label to be updated 'master': The corresponding master bar for this task @@ -40,11 +40,14 @@ def __init__(self, object): self.color = choice(["green", "magenta", "cyan", "blue", "red", "yellow"]) self.pbar = None # type: tqdm self.keydata = {} - self.pos = 0 + self.position = 0 def emit(self, val): if self.deactivate: return + if val[0] == "set_position": + self.position = val[1] + if val[0] == "finished": if self.pbar is not None: self.pbar.close() @@ -64,7 +67,7 @@ def emit(self, val): if self.pbar is not None: self.pbar.close() desc = str(val[2]).rjust(50) - self.pbar = tqdm(total=val[1], colour=self.color, leave=False, desc=desc, position=self.pos) + self.pbar = tqdm(total=val[1], colour=self.color, leave=False, desc=desc, position=self.position) elif val[0] == "update": self.pbar.update(val[1] - self.pbar.n) @@ -72,3 +75,8 @@ def emit(self, val): desc = str(val[2]).rjust(50) if self.pbar.desc != desc: self.pbar.set_description(desc, refresh=True) + + elif val[0] == "set_text": + desc = str(val[1]).rjust(50) + if self.pbar.desc != desc: + self.pbar.set_description(desc, refresh=True) diff --git a/aequilibrae/utils/signal.py b/aequilibrae/utils/signal.py index d68729dff..8e9146c6c 100644 --- a/aequilibrae/utils/signal.py +++ b/aequilibrae/utils/signal.py @@ -5,15 +5,8 @@ def noop(_): pass -if iutil.find_spec("qgis") is not None: - from PyQt5.QtCore import QThread - from PyQt5.QtCore import pyqtSignal - - class SIGNAL(QThread): - signal = pyqtSignal(str) - - def emit(self, val): - self.signal.emit(val) +if iutil.find_spec("PyQt5") is not None: + from PyQt5.QtCore import pyqtSignal as SIGNAL noop(SIGNAL.__class__) # This should be no-op but it stops PyCharm from "optimising" the above import else: From b914cee6f7ebea8a89ccf64069adc02684029167 Mon Sep 17 00:00:00 2001 From: pveigadecamargo Date: Fri, 9 Aug 2024 11:11:20 +1000 Subject: [PATCH 4/7] updates messaging --- aequilibrae/paths/linear_approximation.py | 2 +- aequilibrae/utils/python_signal.py | 8 +++++--- aequilibrae/utils/signal.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/aequilibrae/paths/linear_approximation.py b/aequilibrae/paths/linear_approximation.py index 7011d7690..2861291b0 100644 --- a/aequilibrae/paths/linear_approximation.py +++ b/aequilibrae/paths/linear_approximation.py @@ -513,7 +513,7 @@ def execute(self): # noqa: C901 copy_three_dimensions( c.results.select_link_od.matrix[name], # matrix being written into np.sum(self.aons[c._id].aux_res.temp_sl_od_matrix, axis=0)[ - idx, :, :, : + idx, :, :, : ], # results after the iteration self.cores, # core count ) diff --git a/aequilibrae/utils/python_signal.py b/aequilibrae/utils/python_signal.py index d8615451e..13c8cae00 100644 --- a/aequilibrae/utils/python_signal.py +++ b/aequilibrae/utils/python_signal.py @@ -1,4 +1,5 @@ import importlib.util as iutil +import os import warnings from random import choice @@ -13,8 +14,7 @@ qgis = iutil.find_spec("qgis") is not None -if missing_tqdm and not qgis: - warnings.warn("No progress bars will be shown. Please install tqdm to see them") +show_status = os.environ.get("SHOW PROGRESS", "FALSE") == "TRUE" class PythonSignal: # type: ignore @@ -34,7 +34,7 @@ class PythonSignal: # type: ignore 'master': The corresponding master bar for this task """ - deactivate = missing_tqdm # by default don't use progress bars in tests + deactivate = not show_status # by default don't use progress bars in tests def __init__(self, object): self.color = choice(["green", "magenta", "cyan", "blue", "red", "yellow"]) @@ -64,6 +64,8 @@ def emit(self, val): self.keydata[val[1]] = val[2] elif val[0] == "start": + if missing_tqdm and not qgis: + warnings.warn("No progress bars will be shown. Please install tqdm to see them") if self.pbar is not None: self.pbar.close() desc = str(val[2]).rjust(50) diff --git a/aequilibrae/utils/signal.py b/aequilibrae/utils/signal.py index 8e9146c6c..5143068f4 100644 --- a/aequilibrae/utils/signal.py +++ b/aequilibrae/utils/signal.py @@ -5,7 +5,7 @@ def noop(_): pass -if iutil.find_spec("PyQt5") is not None: +if iutil.find_spec("qgis") is not None: from PyQt5.QtCore import pyqtSignal as SIGNAL noop(SIGNAL.__class__) # This should be no-op but it stops PyCharm from "optimising" the above import From 3124c2c06967e72c9e039b9a8051cc2a09f4e02e Mon Sep 17 00:00:00 2001 From: pveigadecamargo Date: Fri, 9 Aug 2024 11:11:28 +1000 Subject: [PATCH 5/7] updates messaging --- aequilibrae/utils/interface/worker_thread.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aequilibrae/utils/interface/worker_thread.py b/aequilibrae/utils/interface/worker_thread.py index 6ef9af617..6bce420f9 100644 --- a/aequilibrae/utils/interface/worker_thread.py +++ b/aequilibrae/utils/interface/worker_thread.py @@ -4,6 +4,7 @@ from PyQt5.QtCore import QThread from PyQt5.QtCore import pyqtSignal else: + class QThread: # type: ignore def __init__(self, *arg): pass @@ -24,4 +25,4 @@ def run(self): def stop(self): self.running = False - pass \ No newline at end of file + pass From 4632df767a2d72864b85e0226934407e1207a1e8 Mon Sep 17 00:00:00 2001 From: pveigadecamargo Date: Fri, 9 Aug 2024 13:03:08 +1000 Subject: [PATCH 6/7] updates messaging --- aequilibrae/utils/python_signal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aequilibrae/utils/python_signal.py b/aequilibrae/utils/python_signal.py index 13c8cae00..d35a08589 100644 --- a/aequilibrae/utils/python_signal.py +++ b/aequilibrae/utils/python_signal.py @@ -14,7 +14,7 @@ qgis = iutil.find_spec("qgis") is not None -show_status = os.environ.get("SHOW PROGRESS", "FALSE") == "TRUE" +show_status = os.environ.get("AEQ_SHOW_PROGRESS", "FALSE") == "TRUE" class PythonSignal: # type: ignore From c62cd19791fd109d6d0eec14f8c4d128b6271134 Mon Sep 17 00:00:00 2001 From: pveigadecamargo Date: Thu, 10 Oct 2024 21:09:51 +1000 Subject: [PATCH 7/7] Reinstates worker thread --- aequilibrae/utils/qgis_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aequilibrae/utils/qgis_utils.py b/aequilibrae/utils/qgis_utils.py index b87a159ea..d066031a2 100644 --- a/aequilibrae/utils/qgis_utils.py +++ b/aequilibrae/utils/qgis_utils.py @@ -2,3 +2,4 @@ # If we can find the qgis module to import ... we are running inside qgis inside_qgis = iutil.find_spec("qgis") is not None +rtree_avail = iutil.find_spec("rtree") is not None