Commit c6a8b213 authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

Fixed NoneTypeError in ProgressBar in case sys.stderr is None. Added tests for processing module.

parent f9510154
Pipeline #35170 passed with stage
in 3 minutes and 36 seconds
...@@ -99,6 +99,8 @@ class ProgressBar(object): ...@@ -99,6 +99,8 @@ class ProgressBar(object):
self.use_as_cb = use_as_callback self.use_as_cb = use_as_callback
self.out = out self.out = out
self._percdone = list(range(10, 110, 10))
def print_progress(self, percent): def print_progress(self, percent):
"""Print progress. """Print progress.
...@@ -108,11 +110,14 @@ class ProgressBar(object): ...@@ -108,11 +110,14 @@ class ProgressBar(object):
:return: :return:
""" """
if self.Timer.timed_out: if self.Timer.timed_out:
self.out.flush() if self.out is not None:
self.out.flush()
if self.use_as_cb: if self.use_as_cb:
# raise a KeyBoardInterrupt instead of a TimeOutError # raise a KeyBoardInterrupt instead of a TimeOutError
# as this is catchable by gdal.GetLastException() # as this is catchable by gdal.GetLastException()
raise KeyboardInterrupt() raise KeyboardInterrupt()
else:
raise TimeoutError(f'No progress for {self.timeout} seconds.')
formatStr = "{0:." + str(self.decimals) + "f}" formatStr = "{0:." + str(self.decimals) + "f}"
percents = formatStr.format(percent) percents = formatStr.format(percent)
...@@ -120,17 +125,30 @@ class ProgressBar(object): ...@@ -120,17 +125,30 @@ class ProgressBar(object):
# bar = '█' * filledLength + '-' * (barLength - filledLength) # this is not compatible to shell console # bar = '█' * filledLength + '-' * (barLength - filledLength) # this is not compatible to shell console
bar = '=' * filledLength + '-' * (self.barLength - filledLength) bar = '=' * filledLength + '-' * (self.barLength - filledLength)
# reset the cursor to the beginning of the line and allows to write over what was previously on the line if self.out is not None:
self.out.write('\r') # reset the cursor to the beginning of the line and allows to write over what was previously on the line
self.out.write('\r')
# [%s/%s] numberDone # [%s/%s] numberDone
suffix = self.suffix if not self.show_elapsed else '%s => %s' % (self.suffix, self.Timer.elapsed) suffix = self.suffix if not self.show_elapsed else '%s => %s' % (self.suffix, self.Timer.elapsed)
self.out.write('%s |%s| %s%s %s' % (self.prefix, bar, percents, '%', suffix)) self.out.write('%s |%s| %s%s %s' % (self.prefix, bar, percents, '%', suffix))
if percent >= 100.: if percent >= 100.:
self.out.write('\n') self.out.write('\n')
self.out.flush() self.out.flush()
else:
# in some environments, sys.stderr can also be None
# pydocs: usually Windows GUI apps that aren’t connected to a console and Python apps started with pythonw
try:
percnext = self._percdone[0]
if percent >= percnext:
print(f'{percents} %')
self._percdone.pop(0)
except IndexError: # pragma: no cover
pass
def __call__(self, percent01, message, user_data): def __call__(self, percent01, message, user_data):
"""Allow ProgressBar instances to be callable and thus to be used as callback function, e.g., for GDAL. """Allow ProgressBar instances to be callable and thus to be used as callback function, e.g., for GDAL.
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# py_tools_ds - A collection of geospatial data analysis tools that simplify standard
# operations when handling geospatial raster and vector data as well as projections.
#
# Copyright (C) 2016-2021
# - Daniel Scheffler (GFZ Potsdam, daniel.scheffler@gfz-potsdam.de)
# - Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences Potsdam,
# Germany (https://www.gfz-potsdam.de/)
#
# This software was developed within the context of the GeoMultiSens project funded
# by the German Federal Ministry of Education and Research
# (project grant code: 01 IS 14 010 A-C).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
test_progress_mon
-----------------
Tests for `py_tools_ds.processing.progress_mon` module.
"""
import unittest
from time import sleep
from py_tools_ds.processing.progress_mon import ProgressBar
class Test_ProgressBar(unittest.TestCase):
def test_print_progress(self):
bar = ProgressBar(prefix='\tprogress:')
for i in range(100):
bar.print_progress((i + 1) / 100 * 100)
def test_timeout(self):
with self.assertRaises(TimeoutError):
bar = ProgressBar(prefix='\tprogress:', timeout=0.1)
for i in range(5):
bar.print_progress((i + 1) / 5 * 100)
sleep(0.2)
def test_stderr_is_none(self):
bar = ProgressBar(prefix='\tprogress:', out=None)
for i in range(73):
bar.print_progress((i + 1) / 73 * 100)
if __name__ == '__main__':
unittest.main()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment