13
13
14
14
import importlib .resources
15
15
import json
16
+ import logging
16
17
import re
17
18
import sys
18
- import urllib .request
19
- from typing import Optional
19
+ from typing import Any , Optional
20
20
21
- import requests
21
+ import httpx
22
22
23
23
import synapseclient
24
24
25
- _VERSION_URL = "https://raw.githubusercontent.com/Sage-Bionetworks/synapsePythonClient/master/synapseclient/synapsePythonClient" # noqa
26
25
_PYPI_JSON_URL = "https://pypi.org/pypi/synapseclient/json"
27
26
_RELEASE_NOTES_URL = "https://python-docs.synapse.org/news/"
28
27
@@ -31,6 +30,7 @@ def version_check(
31
30
current_version : Optional [str ] = None ,
32
31
check_for_point_releases : bool = False ,
33
32
use_local_metadata : bool = False ,
33
+ logger : logging .Logger = None ,
34
34
) -> bool :
35
35
"""
36
36
Gets the latest version information from version_url and check against the current version.
@@ -39,25 +39,26 @@ def version_check(
39
39
This wraps the _version_check function in a try except block.
40
40
The purpose of this is so that no exception caught running the version check stops the client from running.
41
41
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.
44
44
Defaults to None.
45
45
This argument is mainly used for testing.
46
- check_for_point_releases (bool, optional) :
46
+ check_for_point_releases:
47
47
Defaults to False.
48
48
If True, The whole package versions will be compared (ie. 1.0.0)
49
49
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:
51
51
Defaults to False.
52
52
If True, importlib.resources will be used to get the latest version fo the package
53
53
If False, the latest version fo the package will be taken from Pypi
54
+ logger: a logger for logging output
54
55
55
56
Returns:
56
57
bool: True if current version is the latest release (or higher) version, otherwise False.
57
58
"""
58
59
try :
59
60
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
61
62
):
62
63
return False
63
64
@@ -69,29 +70,78 @@ def version_check(
69
70
return True
70
71
71
72
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 + "\n Your 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
+
72
121
def _version_check (
73
122
current_version : Optional [str ] = None ,
74
123
check_for_point_releases : bool = False ,
75
124
use_local_metadata : bool = False ,
125
+ logger : logging .Logger = None ,
76
126
) -> bool :
77
127
"""
78
128
Gets the latest version information from version_url and check against the current version.
79
129
Recommends upgrade, if a newer version exists.
80
130
81
131
This has been split of from the version_check function to make testing easier.
82
132
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.
85
135
Defaults to None.
86
136
This argument is mainly used for testing.
87
- check_for_point_releases (bool, optional) :
137
+ check_for_point_releases:
88
138
Defaults to False.
89
139
If True, The whole package versions will be compared (ie. 1.0.0)
90
140
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:
92
142
Defaults to False.
93
143
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
95
145
96
146
Returns:
97
147
bool: True if current version is the latest release (or higher) version, otherwise False.
@@ -110,19 +160,38 @@ def _version_check(
110
160
levels = 3 if check_for_point_releases else 2
111
161
112
162
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 ()
114
171
return False
115
172
return True
116
173
117
174
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
+
118
187
def _get_version_info_from_pypi () -> str :
119
188
"""Gets the current release version from PyPi
120
189
121
190
Returns:
122
191
str: The current release version
123
192
"""
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 )
126
195
version = data ["info" ]["version" ]
127
196
assert isinstance (version , str )
128
197
return version
@@ -134,10 +203,10 @@ def _is_current_version_behind(
134
203
"""
135
204
Tests if the current version of the package is behind the latest version.
136
205
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:
141
210
level 1: major versions
142
211
level 2: minor versions
143
212
level 3: patch versions
@@ -161,79 +230,22 @@ def _is_current_version_behind(
161
230
return current_version_int_tuple < latest_version_int_tuple
162
231
163
232
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
- "\n UPGRADE AVAILABLE\n \n A 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
+ "\n UPGRADE AVAILABLE\n \n "
236
+ f"A more recent version of the Synapse Client ({ latest_version } ) is available."
179
237
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 "
181
239
)
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
187
241
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.
192
242
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 "
202
247
)
203
-
204
- if _version_tuple (synapseclient .__version__ , levels = 3 ) < _version_tuple (
205
- release_version_info ["latestVersion" ], levels = 3
206
- ):
207
- print (
208
- "\n UPGRADE AVAILABLE\n \n A 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 ("\n Your 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
237
249
238
250
239
251
def _strip_dev_suffix (version ):
@@ -255,9 +267,9 @@ def _version_tuple(version: str, levels: int = 2) -> tuple:
255
267
If the number of levels is lesser than the levels argument(x),
256
268
"0" strings are used to pad out the return value.
257
269
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:
261
273
Defaults to 2.
262
274
The number of levels deep in the package version to return. "1.0.0", for example:
263
275
levels=1: only the major version ("1")
@@ -274,39 +286,6 @@ def _version_tuple(version: str, levels: int = 2) -> tuple:
274
286
return tuple (v )
275
287
276
288
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
-
310
289
# If this file is run as a script, print current version
311
290
# then perform version check
312
291
if __name__ == "__main__" :
0 commit comments