Skip to content

Commit cee95b3

Browse files
committed
Bryans suggestions
1 parent 8663e45 commit cee95b3

File tree

2 files changed

+104
-126
lines changed

2 files changed

+104
-126
lines changed

synapseclient/core/version_check.py

Lines changed: 104 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@
1313

1414
import importlib.resources
1515
import json
16+
import logging
1617
import re
1718
import sys
18-
import urllib.request
19-
from typing import Optional
19+
from typing import Any, Optional
2020

21-
import requests
21+
import httpx
2222

2323
import synapseclient
2424

25-
_VERSION_URL = "https://raw.githubusercontent.com/Sage-Bionetworks/synapsePythonClient/master/synapseclient/synapsePythonClient" # noqa
2625
_PYPI_JSON_URL = "https://pypi.org/pypi/synapseclient/json"
2726
_RELEASE_NOTES_URL = "https://python-docs.synapse.org/news/"
2827

@@ -31,6 +30,7 @@ def version_check(
3130
current_version: Optional[str] = None,
3231
check_for_point_releases: bool = False,
3332
use_local_metadata: bool = False,
33+
logger: logging.Logger = None,
3434
) -> bool:
3535
"""
3636
Gets the latest version information from version_url and check against the current version.
@@ -39,25 +39,26 @@ def version_check(
3939
This wraps the _version_check function in a try except block.
4040
The purpose of this is so that no exception caught running the version check stops the client from running.
4141
42-
Args:
43-
current_version (Optional[str], optional): The current version of the package.
42+
Arguments:
43+
current_version: The current version of the package.
4444
Defaults to None.
4545
This argument is mainly used for testing.
46-
check_for_point_releases (bool, optional):
46+
check_for_point_releases:
4747
Defaults to False.
4848
If True, The whole package versions will be compared (ie. 1.0.0)
4949
If False, only the major and minor package version will be compared (ie. 1.0)
50-
use_local_metadata (bool, optional):
50+
use_local_metadata:
5151
Defaults to False.
5252
If True, importlib.resources will be used to get the latest version fo the package
5353
If False, the latest version fo the package will be taken from Pypi
54+
logger: a logger for logging output
5455
5556
Returns:
5657
bool: True if current version is the latest release (or higher) version, otherwise False.
5758
"""
5859
try:
5960
if not _version_check(
60-
current_version, check_for_point_releases, use_local_metadata
61+
current_version, check_for_point_releases, use_local_metadata, logger
6162
):
6263
return False
6364

@@ -69,29 +70,78 @@ def version_check(
6970
return True
7071

7172

73+
def check_for_updates(logger: logging.Logger = None):
74+
"""
75+
Check for the existence of newer versions of the client,
76+
reporting both current release version and development version.
77+
78+
For help installing development versions of the client,
79+
see the [README.md](https://github.com/Sage-Bionetworks/synapsePythonClient#installation).
80+
81+
Arguments:
82+
logger: a logger for logging output
83+
84+
"""
85+
current_version = synapseclient.__version__
86+
latest_version = _get_version_info_from_pypi()
87+
88+
msg = (
89+
"Python Synapse Client\n"
90+
f"currently running version: {current_version}\n"
91+
f"latest release version: {latest_version}\n"
92+
)
93+
if _is_current_version_behind(current_version, latest_version, levels=3):
94+
msg = msg + _create_package_behind_message(current_version, latest_version)
95+
else:
96+
msg = msg + "\nYour Synapse client is up to date!\n"
97+
98+
if logger:
99+
logger.info(msg)
100+
else:
101+
sys.stdout.write(msg)
102+
sys.stdout.flush()
103+
104+
105+
def release_notes(logger: logging.Logger = None):
106+
"""
107+
Print release notes for the latest release
108+
109+
Arguments:
110+
logger: a logger for logging output
111+
"""
112+
latest_version = _get_version_info_from_pypi()
113+
msg = _create_release_notes_message(latest_version)
114+
if logger:
115+
logger.info(msg)
116+
else:
117+
sys.stdout.write(msg)
118+
sys.stdout.flush()
119+
120+
72121
def _version_check(
73122
current_version: Optional[str] = None,
74123
check_for_point_releases: bool = False,
75124
use_local_metadata: bool = False,
125+
logger: logging.Logger = None,
76126
) -> bool:
77127
"""
78128
Gets the latest version information from version_url and check against the current version.
79129
Recommends upgrade, if a newer version exists.
80130
81131
This has been split of from the version_check function to make testing easier.
82132
83-
Args:
84-
current_version (Optional[str], optional): The current version of the package.
133+
Arguments:
134+
current_version: The current version of the package.
85135
Defaults to None.
86136
This argument is mainly used for testing.
87-
check_for_point_releases (bool, optional):
137+
check_for_point_releases:
88138
Defaults to False.
89139
If True, The whole package versions will be compared (ie. 1.0.0)
90140
If False, only the major and minor package version will be compared (ie. 1.0)
91-
use_local_metadata (bool, optional):
141+
use_local_metadata:
92142
Defaults to False.
93143
If True, importlib.resources will be used to get the latest version fo the package
94-
If False, the latest version fo the package will be taken from Pypi
144+
logger: a logger for logging output
95145
96146
Returns:
97147
bool: True if current version is the latest release (or higher) version, otherwise False.
@@ -110,19 +160,38 @@ def _version_check(
110160
levels = 3 if check_for_point_releases else 2
111161

112162
if _is_current_version_behind(current_version, latest_version, levels):
113-
_write_package_behind_messages(current_version, latest_version)
163+
msg1 = _create_package_behind_message(current_version, latest_version)
164+
msg2 = _create_release_notes_message(latest_version)
165+
msg = msg1 + msg2
166+
if logger:
167+
logger.info(msg)
168+
else:
169+
sys.stdout.write(msg)
170+
sys.stdout.flush()
114171
return False
115172
return True
116173

117174

175+
def _get_local_package_metadata() -> dict[str, Any]:
176+
"""Gets version info locally, using importlib.resources
177+
178+
Returns:
179+
dict[str, Any]: This will have various fields relating the version of the client
180+
"""
181+
ref = importlib.resources.files("synapseclient").joinpath("synapsePythonClient")
182+
with ref.open("r") as fp:
183+
pkg_metadata = json.loads(fp.read())
184+
return pkg_metadata
185+
186+
118187
def _get_version_info_from_pypi() -> str:
119188
"""Gets the current release version from PyPi
120189
121190
Returns:
122191
str: The current release version
123192
"""
124-
with urllib.request.urlopen(_PYPI_JSON_URL) as url:
125-
data = json.load(url)
193+
content = httpx.get(_PYPI_JSON_URL)
194+
data = json.load(content)
126195
version = data["info"]["version"]
127196
assert isinstance(version, str)
128197
return version
@@ -134,10 +203,10 @@ def _is_current_version_behind(
134203
"""
135204
Tests if the current version of the package is behind the latest version.
136205
137-
Args:
138-
current_version (str): The current version of a package
139-
latest_version (str): The latest version of a package
140-
levels (int): The levels of the packages to check. For example:
206+
Arguments:
207+
current_version: The current version of a package
208+
latest_version: The latest version of a package
209+
levels: The levels of the packages to check. For example:
141210
level 1: major versions
142211
level 2: minor versions
143212
level 3: patch versions
@@ -161,79 +230,22 @@ def _is_current_version_behind(
161230
return current_version_int_tuple < latest_version_int_tuple
162231

163232

164-
def _write_package_behind_messages(
165-
current_version: str,
166-
latest_version: str,
167-
) -> None:
168-
"""
169-
This writes the output message for when the installed package version is behind the
170-
most recent release.
171-
172-
Args:
173-
current_version (str): The current version of a package
174-
latest_version (str): The latest version of a package
175-
"""
176-
sys.stderr.write(
177-
"\nUPGRADE AVAILABLE\n\nA more recent version of the Synapse Client"
178-
f" ({latest_version}) is available."
233+
def _create_package_behind_message(current_version: str, latest_version: str) -> str:
234+
msg = (
235+
"\nUPGRADE AVAILABLE\n\n"
236+
f"A more recent version of the Synapse Client ({latest_version}) is available."
179237
f" Your version ({current_version}) can be upgraded by typing:\n "
180-
" pip install --upgrade synapseclient\n\n"
238+
"pip install --upgrade synapseclient\n\n"
181239
)
182-
sys.stderr.write(
183-
f"Python Synapse Client version {latest_version}" " release notes\n\n"
184-
)
185-
sys.stderr.write(f"{_RELEASE_NOTES_URL}\n\n")
186-
240+
return msg
187241

188-
def check_for_updates():
189-
"""
190-
Check for the existence of newer versions of the client, reporting both current release version and development
191-
version.
192242

193-
For help installing development versions of the client,
194-
see the [README.md](https://github.com/Sage-Bionetworks/synapsePythonClient#installation).
195-
"""
196-
sys.stderr.write("Python Synapse Client\n")
197-
sys.stderr.write("currently running version: %s\n" % synapseclient.__version__)
198-
199-
release_version_info = _get_version_info(_VERSION_URL)
200-
sys.stderr.write(
201-
"latest release version: %s\n" % release_version_info["latestVersion"]
243+
def _create_release_notes_message(latest_version) -> str:
244+
msg = (
245+
f"Python Synapse Client version {latest_version} release notes\n\n"
246+
f"{_RELEASE_NOTES_URL}\n\n"
202247
)
203-
204-
if _version_tuple(synapseclient.__version__, levels=3) < _version_tuple(
205-
release_version_info["latestVersion"], levels=3
206-
):
207-
print(
208-
"\nUPGRADE AVAILABLE\n\nA more recent version of the Synapse Client (%s) is"
209-
" available. Your version (%s) can be upgraded by typing:\n pip install"
210-
" --upgrade synapseclient\n\n"
211-
% (
212-
release_version_info["latestVersion"],
213-
synapseclient.__version__,
214-
)
215-
)
216-
else:
217-
sys.stderr.write("\nYour Synapse client is up to date!\n")
218-
219-
220-
def release_notes(version_url=None):
221-
"""
222-
Print release notes for the installed version of the client or latest release or development version if version_url
223-
is supplied.
224-
225-
version_url: Defaults to None, meaning release notes for the installed version. Alternatives are:
226-
- synapseclient.version_check._VERSION_URL
227-
- synapseclient.version_check._DEV_VERSION_URL
228-
229-
"""
230-
version_info = _get_version_info(version_url)
231-
sys.stderr.write(
232-
"Python Synapse Client version %s release notes\n\n"
233-
% version_info["latestVersion"]
234-
)
235-
if "releaseNotes" in version_info:
236-
sys.stderr.write(version_info["releaseNotes"] + "\n")
248+
return msg
237249

238250

239251
def _strip_dev_suffix(version):
@@ -255,9 +267,9 @@ def _version_tuple(version: str, levels: int = 2) -> tuple:
255267
If the number of levels is lesser than the levels argument(x),
256268
"0" strings are used to pad out the return value.
257269
258-
Args:
259-
version (str): A package version in string form such as "1.0.0"
260-
levels (int, optional):
270+
Arguments:
271+
version: A package version in string form such as "1.0.0"
272+
levels:
261273
Defaults to 2.
262274
The number of levels deep in the package version to return. "1.0.0", for example:
263275
levels=1: only the major version ("1")
@@ -274,39 +286,6 @@ def _version_tuple(version: str, levels: int = 2) -> tuple:
274286
return tuple(v)
275287

276288

277-
def _get_version_info(version_url: Optional[str] = _VERSION_URL) -> dict:
278-
"""
279-
Gets version info from the version_url argument, or locally
280-
By default this is the Github for the python client
281-
If the version_url argument is None the version info will be obtained locally.
282-
283-
Args:
284-
version_url (str, optional):
285-
Defaults to _VERSION_URL.
286-
The url to get version info from
287-
288-
Returns:
289-
dict: This will have various fields relating the version of the client
290-
"""
291-
if version_url is None:
292-
return _get_local_package_metadata()
293-
headers = {"Accept": "application/json; charset=UTF-8"}
294-
headers.update(synapseclient.USER_AGENT)
295-
return requests.get(version_url, headers=headers).json()
296-
297-
298-
def _get_local_package_metadata() -> dict:
299-
"""Gets version info locally, using importlib.resources
300-
301-
Returns:
302-
dict: This will have various fields relating the version of the client
303-
"""
304-
ref = importlib.resources.files("synapseclient").joinpath("synapsePythonClient")
305-
with ref.open("r") as fp:
306-
pkg_metadata = json.loads(fp.read())
307-
return pkg_metadata
308-
309-
310289
# If this file is run as a script, print current version
311290
# then perform version check
312291
if __name__ == "__main__":

tests/integration/synapseclient/integration_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
client,
2626
)
2727
from synapseclient.core.exceptions import SynapseHTTPError, SynapseNoCredentialsError
28-
from synapseclient.core.version_check import version_check
2928

3029
PUBLIC = 273949 # PrincipalId of public "user"
3130
AUTHENTICATED_USERS = 273948

0 commit comments

Comments
 (0)