diff --git a/integrations/client/test_delphi_epidata.py b/integrations/client/test_delphi_epidata.py index 3b69eb4cf..d788cada2 100644 --- a/integrations/client/test_delphi_epidata.py +++ b/integrations/client/test_delphi_epidata.py @@ -2,8 +2,8 @@ # standard library import time +import json from json import JSONDecodeError -from requests.models import Response from unittest.mock import MagicMock, patch # first party @@ -306,6 +306,30 @@ def test_sandbox(self, get, post): Epidata.debug = False Epidata.sandbox = False + @patch('requests.get') + def test_version_check(self, get): + """Test that the _version_check() function correctly logs a version discrepancy.""" + class MockJson: + def __init__(self, content, status_code): + self.content = content + self.status_code = status_code + def raise_for_status(self): pass + def json(self): return json.loads(self.content) + get.reset_mock() + get.return_value = MockJson(b'{"info": {"version": "0.0.1"}}', 200) + Epidata._version_check() + captured = self.capsys.readouterr() + output = captured.err.splitlines() + self.assertEqual(len(output), 1) + self.assertIn("Client version not up to date", output[0]) + self.assertIn("\'latest_version\': \'0.0.1\'", output[0]) + + @patch('delphi.epidata.client.delphi_epidata.Epidata._version_check') + def test_version_check_once(self, version_check): + """Test that the _version_check() function is only called once on initial module import.""" + from delphi.epidata.client.delphi_epidata import Epidata + version_check.assert_not_called() + def test_geo_value(self): """test different variants of geo types: single, *, multi.""" diff --git a/src/client/delphi_epidata.py b/src/client/delphi_epidata.py index 9c55e0b73..22fd9c1c8 100644 --- a/src/client/delphi_epidata.py +++ b/src/client/delphi_epidata.py @@ -43,8 +43,6 @@ class Epidata: BASE_URL = "https://api.delphi.cmu.edu/epidata" auth = None - client_version = __version__ - debug = False # if True, prints extra logging statements sandbox = False # if True, will not execute any queries @@ -54,6 +52,24 @@ def log(evt, **kwargs): kwargs['timestamp'] = time.strftime("%Y-%m-%d %H:%M:%S %z") return sys.stderr.write(str(kwargs) + "\n") + # Check that this client's version matches the most recent available, runs just once per program execution (on initial module load). + @staticmethod + def _version_check(): + try: + latest_version = requests.get('https://pypi.org/pypi/delphi-epidata/json').json()['info']['version'] + if latest_version != __version__: + Epidata.log( + "Client version not up to date", + client_version=__version__, + latest_version=latest_version + ) + except Exception as e: + Epidata.log("Error getting latest client version", exception=str(e)) + + # Run this once on module load. Use dunder method for Python <= 3.9 compatibility + # https://stackoverflow.com/a/12718272 + _version_check.__func__() + # Helper function to cast values and/or ranges to strings @staticmethod def _listitem(value): diff --git a/src/client/packaging/pypi/CHANGELOG.md b/src/client/packaging/pypi/CHANGELOG.md index e053619c8..3c465e3e3 100644 --- a/src/client/packaging/pypi/CHANGELOG.md +++ b/src/client/packaging/pypi/CHANGELOG.md @@ -3,6 +3,14 @@ All notable future changes to the `delphi_epidata` python client will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). +## [4.1.25] - 2024-07-18 + +### Includes +- https://github.com/cmu-delphi/delphi-epidata/pull/1456 + +### Changed +- Added a one-time check which logs a warning when the newest client version does not match the client version in use. + ## [4.1.24] - 2024-07-09 ### Includes