From 4ed5667b39fc876873187581f8cc4e1868b13c87 Mon Sep 17 00:00:00 2001 From: Bob Weigel Date: Mon, 22 Jun 2026 15:07:45 -0400 Subject: [PATCH 1/6] disable logger warning --- hapiclient/log.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hapiclient/log.py b/hapiclient/log.py index a931104..0ec4cec 100644 --- a/hapiclient/log.py +++ b/hapiclient/log.py @@ -35,11 +35,13 @@ def configure_logging(logging): _logger.addHandler(_handler) if logging is False: if has_user_level or has_user_handlers: - from .util import warning + #from .util import warning if has_user_handlers: - warning("Ignoring logging=False because standard Python logger for 'hapiclient' already configured with handlers.") + pass + #warning("Ignoring logging=False because standard Python logger for 'hapiclient' already configured with handlers.") else: - warning("Ignoring logging=False because standard Python logger for 'hapiclient' already configured with log_level != NOTSET.") + pass + #warning("Ignoring logging=False because standard Python logger for 'hapiclient' already configured with log_level != NOTSET.") else: _logger.setLevel(_logging.WARNING) setattr(_logger, _INTERNAL_LEVEL_ATTR, _logging.WARNING) From 08b1906731d3e035b700a6df9fd94aeb6c9736a5 Mon Sep 17 00:00:00 2001 From: Bob Weigel Date: Mon, 22 Jun 2026 15:53:55 -0400 Subject: [PATCH 2/6] Atomic writes --- hapiclient/cache.py | 34 ++++--------------- hapiclient/hapi.py | 4 +-- hapiclient/util.py | 79 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 73 insertions(+), 44 deletions(-) diff --git a/hapiclient/cache.py b/hapiclient/cache.py index c9cd02b..5105064 100644 --- a/hapiclient/cache.py +++ b/hapiclient/cache.py @@ -125,10 +125,9 @@ def meta_cache_write(meta, SERVER, DATASET, opts): """Write metadata to JSON and PKL cache files.""" import os - import json - import pickle from hapiclient.log import log + from hapiclient.util import write_atomic if not opts["cache"]: return @@ -136,17 +135,11 @@ def meta_cache_write(meta, SERVER, DATASET, opts): paths = meta_cache_paths(SERVER, DATASET, opts['cachedir']) fnamejson, fnamepkl = paths['json'], paths['pkl'] - server_dir = cachedir(opts["cachedir"], SERVER) - os.makedirs(server_dir, exist_ok=True) - log('Writing %s ' % os.path.basename(fnamejson)) - with open(fnamejson, 'w') as f: - json.dump(meta, f, indent=4) + write_atomic(fnamejson, meta) log('Writing %s ' % os.path.basename(fnamepkl)) - with open(fnamepkl, 'wb') as f: - # protocol=2 used for Python 2.7 compatibility. - pickle.dump(meta, f, protocol=2) + write_atomic(fnamepkl, meta) def data_cache_paths(SERVER, DATASET, PARAMETERS, START, STOP, cachedir): @@ -215,11 +208,9 @@ def data_cache_write(data_result, meta, SERVER, DATASET, PARAMETERS, START, STOP """ import os - import pickle - import warnings - import numpy as np from hapiclient.log import log + from hapiclient.util import write_atomic data_paths = data_cache_paths(SERVER, DATASET, PARAMETERS, START, STOP, opts['cachedir']) fnamecsv, fnamebin, fnamenpy, fnamepklx = data_paths['csv'], data_paths['bin'], data_paths['npy'], data_paths['pkl'] @@ -236,20 +227,9 @@ def data_cache_write(data_result, meta, SERVER, DATASET, PARAMETERS, START, STOP # Need to return after meta is updated. return - server_dir = cachedir(opts["cachedir"], SERVER) - os.makedirs(server_dir, exist_ok=True) - log('Writing %s' % os.path.basename(fnamepklx)) - with open(fnamepklx, 'wb') as f: - pickle.dump(meta, f, protocol=2) + write_atomic(fnamepklx, meta) log('Writing %s' % os.path.basename(fnamenpy)) - with warnings.catch_warnings(): - # Ignore warning that occurs when saving Unicode data. - kwargs = { - 'message': r"Stored array in format 3\.0.*", - 'category': UserWarning, - 'module': r"numpy\.lib\.format" - } - warnings.filterwarnings("ignore", **kwargs) - np.save(fnamenpy, data_result) + write_atomic(fnamenpy, data_result) + diff --git a/hapiclient/hapi.py b/hapiclient/hapi.py index 3e58056..23ae3b8 100644 --- a/hapiclient/hapi.py +++ b/hapiclient/hapi.py @@ -66,9 +66,9 @@ def hapi(*args, **kwargs): stop: str or None The end time of the requested data; end times are exclusive - the last data record returned by a HAPI server should have a timestamp - before `start`. If `None`, `stopDate` is used. + before `stop`. If `None`, `stopDate` is used. options: dict - `logging` (``False``) - Log to console + `logging` (``False``) - If ``True``, add a stdout handler to the Python ``logging`` module and set log level to INFO. If the Python ``logging`` module has already been configured for the ``hapiclient`` logger (external handlers or log level set), the ``logging`` kwarg is ignored. `cache` (``True``) - Save responses and processed responses in cachedir diff --git a/hapiclient/util.py b/hapiclient/util.py index 916c8b1..a8159c2 100644 --- a/hapiclient/util.py +++ b/hapiclient/util.py @@ -347,26 +347,19 @@ def get_full_class_name(obj): def urlretrieve(url, fname): - """Download URL to file + """Download URL to file atomically. res = urlretrieve(url, fname) """ - import os - import shutil - - dirname = os.path.dirname(fname) - if not os.path.exists(dirname): - os.makedirs(dirname) + log('Writing') + log(' %s' % url) + log('to') + log(' %s' % fname) + res = urlopen(url) + write_atomic(fname, res) - with open(fname, 'wb') as out: - res = urlopen(url) - log('Writing') - log('%s' % url) - log('to') - log('%s' % os.path.basename(fname)) - shutil.copyfileobj(res, out) - return res + return res def subset_meta(meta, params): @@ -454,3 +447,59 @@ def missing_length(meta, opts): return True return False + + +def write_atomic(path, data): + + import os + import json + import pathlib + import pickle + import secrets + + path = pathlib.Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + tmp_ext = f".{secrets.token_hex(6)}.tmp" + tmp_path = path.with_suffix(path.suffix + tmp_ext) + + try: + + if path.suffix == '.json': + with tmp_path.open('w') as f: + json.dump(data, f, indent=2) + + if path.suffix == '.pkl': + with tmp_path.open('wb') as f: + pickle.dump(data, f, protocol=2) + + if path.suffix == '.npy': + import numpy as np + import warnings + with warnings.catch_warnings(): + # Ignore warning that occurs when saving Unicode data. + kwargs = { + 'message': r"Stored array in format 3\.0.*", + 'category': UserWarning, + 'module': r"numpy\.lib\.format" + } + warnings.filterwarnings("ignore", **kwargs) + with tmp_path.open('wb') as f: + np.save(f, data) + + if path.suffix in ('.bin', '.csv'): + with tmp_path.open('wb') as f: + if isinstance(data, (bytes, bytearray)): + f.write(data) + else: + # Assume a file-like / streaming response object. + import shutil + shutil.copyfileobj(data, f) + + os.replace(tmp_path, path) + + except Exception: + warning(f"Failed to write cache file {path}.") + try: + tmp_path.unlink() + except OSError: + warning(f"Failed to remove temporary cache file {tmp_path}.") From 41173d08be172508faa0b0c4dce68774f1a14db1 Mon Sep 17 00:00:00 2001 From: Bob Weigel Date: Thu, 25 Jun 2026 17:45:31 -0400 Subject: [PATCH 3/6] test write_atomic --- hapiclient/cache.py | 1 - hapiclient/util.py | 28 ++++++++------- test/test_hapi_data_requests.py | 64 +++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/hapiclient/cache.py b/hapiclient/cache.py index 5105064..2ab35e7 100644 --- a/hapiclient/cache.py +++ b/hapiclient/cache.py @@ -232,4 +232,3 @@ def data_cache_write(data_result, meta, SERVER, DATASET, PARAMETERS, START, STOP log('Writing %s' % os.path.basename(fnamenpy)) write_atomic(fnamenpy, data_result) - diff --git a/hapiclient/util.py b/hapiclient/util.py index a8159c2..7f4533a 100644 --- a/hapiclient/util.py +++ b/hapiclient/util.py @@ -214,7 +214,7 @@ def prefix(): import platform prefix = "\033[0;31mHAPIError:\033[0m " if platform.system() == 'Windows' and pythonshell() == 'shell': - prefix = "HAPIError: " + prefix = "HAPIError: " return prefix @@ -222,7 +222,7 @@ def exception_handler_ipython(self, exc_tuple=None, filename=None, tb_offset=None, exception_only=False, running_compiled_code=False): - + exception = sys.exc_info() if not debug and exception[0].__name__ == "HAPIError": sys.stderr.write(prefix() + str(exception[1])) @@ -387,7 +387,7 @@ def subset_meta(meta, params): pa = [meta['parameters'][0]] # First parameter is always the time parameter params_reordered = [] # Re-ordered params - # If time parameter explicity requested, put it first in params_reordered. + # If time parameter explicitly requested, put it first in params_reordered. if meta['parameters'][0]['name'] in p: params_reordered = [meta['parameters'][0]['name']] @@ -453,13 +453,16 @@ def write_atomic(path, data): import os import json - import pathlib import pickle + import pathlib import secrets + import warnings + + import numpy path = pathlib.Path(path) path.parent.mkdir(parents=True, exist_ok=True) - tmp_ext = f".{secrets.token_hex(6)}.tmp" + tmp_ext = f".{secrets.token_hex(3)}.tmp" tmp_path = path.with_suffix(path.suffix + tmp_ext) try: @@ -473,8 +476,6 @@ def write_atomic(path, data): pickle.dump(data, f, protocol=2) if path.suffix == '.npy': - import numpy as np - import warnings with warnings.catch_warnings(): # Ignore warning that occurs when saving Unicode data. kwargs = { @@ -484,7 +485,7 @@ def write_atomic(path, data): } warnings.filterwarnings("ignore", **kwargs) with tmp_path.open('wb') as f: - np.save(f, data) + numpy.save(f, data) if path.suffix in ('.bin', '.csv'): with tmp_path.open('wb') as f: @@ -495,11 +496,14 @@ def write_atomic(path, data): import shutil shutil.copyfileobj(data, f) - os.replace(tmp_path, path) + try: + os.replace(tmp_path, path) + except Exception as e: + warning(f"Failed to rename cache file from {tmp_path} to {path}: {e}") - except Exception: - warning(f"Failed to write cache file {path}.") + except Exception as e: + warning(f"Failed to write cache file {tmp_path}: {e}") try: tmp_path.unlink() except OSError: - warning(f"Failed to remove temporary cache file {tmp_path}.") + warning(f"Failed to remove temporary cache file {tmp_path}") \ No newline at end of file diff --git a/test/test_hapi_data_requests.py b/test/test_hapi_data_requests.py index 64c9f16..3917661 100644 --- a/test/test_hapi_data_requests.py +++ b/test/test_hapi_data_requests.py @@ -116,6 +116,68 @@ def test_cache_short(): assert compare.equal(data, data2) +def test_cache_error(): + + from unittest.mock import patch + + import io + import contextlib + import pathlib + import tempfile + from hapiclient.util import write_atomic + + def assert_warns(fn, expected): + buf = io.StringIO() + with contextlib.redirect_stderr(buf): + fn() + print(buf.getvalue()) + assert expected in buf.getvalue(), \ + f"Expected '{expected}' in stderr: {buf.getvalue()!r}" + + with tempfile.TemporaryDirectory() as tmpdir: + path = pathlib.Path(tmpdir) / 'test.json' + data = {'key': 'value'} + + # Simulate write failure + with patch('json.dump', side_effect=OSError('No space left on device')): + assert_warns(lambda: write_atomic(str(path), data), 'Failed to write cache file') + assert not path.exists(), 'File should not exist after write failure' + + # Simulate os.replace failure after successful write + with patch('os.replace', side_effect=OSError('Permission denied')): + assert_warns(lambda: write_atomic(str(path), data), 'Failed to rename cache file from') + assert not path.exists(), 'File should not exist after rename failure' + + # Simulate write failure AND unlink failure + with patch('json.dump', side_effect=OSError('No space left on device')), \ + patch('pathlib.Path.unlink', side_effect=OSError('Permission denied')): + assert_warns(lambda: write_atomic(str(path), data), 'Failed to remove temporary cache file') + + # Simulate successful write + write_atomic(str(path), data) + assert path.exists(), 'File should exist after successful write' + + dataset = 'dataset1' + start = '1970-01-01' + stop = '1970-01-01T00:00:03' + + opts = {**kwargs, 'cache': True, 'usecache': False} + + with patch('pickle.dump', side_effect=OSError('No space left on device')): + assert_warns(lambda: hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts), + 'Failed to write cache file') + + with patch('os.replace', side_effect=OSError('Permission denied')): + assert_warns(lambda: hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts), + 'Failed to rename cache file from') + + with patch('pickle.dump', side_effect=OSError('No space left on device')), \ + patch('pathlib.Path.unlink', side_effect=OSError('Permission denied')): + assert_warns(lambda: hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts), + 'Failed to remove temporary cache file') + + + def test_subset_short(): dataset = 'dataset1' @@ -243,6 +305,8 @@ def test_empty_response(): if __name__ == '__main__': + test_cache_error() + exit() test_empty_response() test_subset_short() test_reader_timing_short() From 827e8994ed2848bac955e233cbd323e284537829 Mon Sep 17 00:00:00 2001 From: Bob Weigel Date: Fri, 26 Jun 2026 09:36:07 -0400 Subject: [PATCH 4/6] move cache tests into single file --- test/test_cache.py | 119 ++++++++++++++++++++++++++++++++ test/test_hapi_data_requests.py | 85 +---------------------- 2 files changed, 120 insertions(+), 84 deletions(-) create mode 100644 test/test_cache.py diff --git a/test/test_cache.py b/test/test_cache.py new file mode 100644 index 0000000..32ef6fd --- /dev/null +++ b/test/test_cache.py @@ -0,0 +1,119 @@ +# See ../README.md for instructions on running tests. +import shutil + +from hapiclient.hapi import hapi + +from util import compare + +from util.get_logger import get_logger +logger = get_logger(__name__) + +kwargs = { + 'cache': False, + 'usecache': False, + 'cachedir': '/tmp/hapi-data', + 'logging': False +} + +server = 'http://hapi-server.org/servers/TestData2.0/hapi' +dataset = 'dataset1' +start = '1970-01-01' +stop = '1970-01-01T00:00:03' + +def test_cache_short(): + + # Compare read with empty cache with read with hot cache and usecache=True + + opts = {**kwargs, 'cache': True} + + opts['usecache'] = False + shutil.rmtree(opts['cachedir'], ignore_errors=True) + data, _ = hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts) + + opts['usecache'] = True + data2, _ = hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts) + + assert compare.equal(data, data2) + + +def test_cache_error(): + + from unittest.mock import patch + + import io + import contextlib + import pathlib + import tempfile + from hapiclient.util import write_atomic + + def assert_warns(fn, expected): + buf = io.StringIO() + with contextlib.redirect_stderr(buf): + result = fn() + print(buf.getvalue()) + msg = f"Expected '{expected}' in stderr: {buf.getvalue()!r}" + assert expected in buf.getvalue(), msg + return result + + # Direct calls to write_atomic() + with tempfile.TemporaryDirectory() as tmpdir: + path = pathlib.Path(tmpdir) / 'test.json' + data = {'key': 'value'} + + def call_write_atomic(): + write_atomic(str(path), data) + + # Simulate write failure + with patch('json.dump', side_effect=OSError('No space left on device')): + assert_warns(call_write_atomic, 'Failed to write cache file') + assert not path.exists(), 'File should not exist after write failure' + + # Simulate os.replace failure after successful write + with patch('os.replace', side_effect=OSError('Permission denied')): + assert_warns(call_write_atomic, 'Failed to rename cache file from') + assert not path.exists(), 'File should not exist after rename failure' + + # Simulate write failure AND unlink failure + patch1 = patch('json.dump', side_effect=OSError('No space left on device')) + patch2 = patch('pathlib.Path.unlink', side_effect=OSError('Permission denied')) + with patch1, patch2: + assert_warns(call_write_atomic, 'Failed to remove temporary cache file') + + # Simulate successful write + write_atomic(str(path), data) + assert path.exists(), 'File should exist after successful write' + + + # Indirect calls to write_atomic() + dataset = 'dataset1' + start = '1970-01-01' + stop = '1970-01-01T00:00:03' + + opts = {**kwargs, 'cache': True, 'usecache': False} + + def call_hapi(): + data, meta = hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts) + return data, meta + + def assert_data_valid(data): + msg = hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts) + assert data['Time'][0] == b'1970-01-01T00:00:00.000Z', msg + + with patch('pickle.dump', side_effect=OSError('No space left on device')): + data, _ = assert_warns(call_hapi, 'Failed to write cache file') + assert_data_valid(data) + + with patch('os.replace', side_effect=OSError('Permission denied')): + data, _ = assert_warns(call_hapi, 'Failed to rename cache file from') + assert_data_valid(data) + + p1 = patch('pickle.dump', side_effect=OSError('No space left on device')) + p2 = patch('pathlib.Path.unlink', side_effect=OSError('Permission denied')) + with p1, p2: + data, _ = assert_warns(call_hapi, 'Failed to remove temporary cache file') + assert_data_valid(data) + + +if __name__ == '__main__': + test_cache_short() + test_cache_error() \ No newline at end of file diff --git a/test/test_hapi_data_requests.py b/test/test_hapi_data_requests.py index 3917661..e6caa69 100644 --- a/test/test_hapi_data_requests.py +++ b/test/test_hapi_data_requests.py @@ -97,87 +97,6 @@ def test_server(version): pytest.fail("test_server('%s') raised: %s" % (version, e)) -def test_cache_short(): - - # Compare read with empty cache with read with hot cache and usecache=True - dataset = 'dataset1' - start = '1970-01-01' - stop = '1970-01-01T00:00:03' - - opts = {**kwargs, 'cache': True} - - opts['usecache'] = False - shutil.rmtree(opts['cachedir'], ignore_errors=True) - data, meta = hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts) - - opts['usecache'] = True - data2, meta2 = hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts) - - assert compare.equal(data, data2) - - -def test_cache_error(): - - from unittest.mock import patch - - import io - import contextlib - import pathlib - import tempfile - from hapiclient.util import write_atomic - - def assert_warns(fn, expected): - buf = io.StringIO() - with contextlib.redirect_stderr(buf): - fn() - print(buf.getvalue()) - assert expected in buf.getvalue(), \ - f"Expected '{expected}' in stderr: {buf.getvalue()!r}" - - with tempfile.TemporaryDirectory() as tmpdir: - path = pathlib.Path(tmpdir) / 'test.json' - data = {'key': 'value'} - - # Simulate write failure - with patch('json.dump', side_effect=OSError('No space left on device')): - assert_warns(lambda: write_atomic(str(path), data), 'Failed to write cache file') - assert not path.exists(), 'File should not exist after write failure' - - # Simulate os.replace failure after successful write - with patch('os.replace', side_effect=OSError('Permission denied')): - assert_warns(lambda: write_atomic(str(path), data), 'Failed to rename cache file from') - assert not path.exists(), 'File should not exist after rename failure' - - # Simulate write failure AND unlink failure - with patch('json.dump', side_effect=OSError('No space left on device')), \ - patch('pathlib.Path.unlink', side_effect=OSError('Permission denied')): - assert_warns(lambda: write_atomic(str(path), data), 'Failed to remove temporary cache file') - - # Simulate successful write - write_atomic(str(path), data) - assert path.exists(), 'File should exist after successful write' - - dataset = 'dataset1' - start = '1970-01-01' - stop = '1970-01-01T00:00:03' - - opts = {**kwargs, 'cache': True, 'usecache': False} - - with patch('pickle.dump', side_effect=OSError('No space left on device')): - assert_warns(lambda: hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts), - 'Failed to write cache file') - - with patch('os.replace', side_effect=OSError('Permission denied')): - assert_warns(lambda: hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts), - 'Failed to rename cache file from') - - with patch('pickle.dump', side_effect=OSError('No space left on device')), \ - patch('pathlib.Path.unlink', side_effect=OSError('Permission denied')): - assert_warns(lambda: hapi(server, dataset, 'scalarint,vectorint', start, stop, **opts), - 'Failed to remove temporary cache file') - - - def test_subset_short(): dataset = 'dataset1' @@ -274,6 +193,7 @@ def test_unicode(): assert compare.read(server, dataset, parameter, run, opts.copy(), logger=logger) assert compare.cache(server, dataset, parameter, opts.copy(), logger=logger) + def test_empty_response(): from hapiclient import hapi @@ -305,14 +225,11 @@ def test_empty_response(): if __name__ == '__main__': - test_cache_error() - exit() test_empty_response() test_subset_short() test_reader_timing_short() test_reader_timing_long() test_all_test_servers() test_subset_short() - test_cache_short() test_request2path() test_unicode() From 7699f6f8c38783a7476a5bef1e7e94ed3ef2e642 Mon Sep 17 00:00:00 2001 From: Bob Weigel Date: Fri, 26 Jun 2026 13:17:07 -0400 Subject: [PATCH 5/6] test logging --- test/test_hapitime2datetime.py | 6 +++--- tox.ini | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/test_hapitime2datetime.py b/test/test_hapitime2datetime.py index c2c0323..b8fb272 100644 --- a/test/test_hapitime2datetime.py +++ b/test/test_hapitime2datetime.py @@ -27,7 +27,7 @@ def test_api(): ] for Time in times: - logger.info(" Testing hapitime2datetime(" + str(Time) + ")") + logger.debug(" Testing hapitime2datetime(" + str(Time) + ")") t = hapitime2datetime(Time) assert t[0].strftime("%Y-%m-%dT%H:%M:%S.%fZ") == expected _assert_utc(t[0]) @@ -35,7 +35,7 @@ def test_api(): def test_parsing(): - logger.info("test_parsing()") + logger.debug("test_parsing()") expected = '1989-01-01T00:00:00.000000Z' @@ -76,7 +76,7 @@ def test_parsing(): ] for i in range(len(dts)): - logger.info(" Testing hapitime2datetime('" + str(dts[i]) + "')") + logger.debug(" Testing hapitime2datetime('" + str(dts[i]) + "')") t = hapitime2datetime(dts[i]) assert t[0].strftime("%Y-%m-%dT%H:%M:%S.%fZ") == expected _assert_utc(t[0]) diff --git a/tox.ini b/tox.ini index c205315..b8e0bb5 100644 --- a/tox.ini +++ b/tox.ini @@ -18,7 +18,7 @@ deps = pytest deepdiff<9 commands = - pytest -s -v -m 'not long' {posargs} + pytest -v -m 'not long' {posargs} # Use `tox -e long-test` to run `long` tests. [testenv:long-test] @@ -28,4 +28,3 @@ deps = deepdiff<9 commands = python -m pytest -v -m 'long' test/test_hapi_data_requests.py - From 31c33f0737809578174099c70b6824ff4fd66be3 Mon Sep 17 00:00:00 2001 From: Bob Weigel Date: Fri, 26 Jun 2026 13:31:27 -0400 Subject: [PATCH 6/6] clean-up --- hapiclient/data.py | 2 +- hapiclient/util.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hapiclient/data.py b/hapiclient/data.py index c0659f1..a69ca87 100644 --- a/hapiclient/data.py +++ b/hapiclient/data.py @@ -22,7 +22,7 @@ def data(SERVER, DATASET, PARAMETERS, START, STOP, opts): log('STOP was given as None. Getting stopDate for dataset.') meta = info(SERVER, DATASET, None, opts) STOP = meta['stopDate'] - log('Using STOP = {STOP}') + log(f'Using STOP = {STOP}') tic_totalTime = time.time() diff --git a/hapiclient/util.py b/hapiclient/util.py index 7f4533a..29d7c2a 100644 --- a/hapiclient/util.py +++ b/hapiclient/util.py @@ -197,7 +197,6 @@ def error(msg, debug=False): from inspect import stack from os import path - debug = False if pythonshell() != 'shell': try: from IPython.core.interactiveshell import InteractiveShell